2008-08-22 7 views
84

J'écris un utilitaire Java qui m'aide à générer des charges de données pour les tests de performance. Ce serait vraiment cool d'être capable de spécifier une regex pour Strings afin que mon générateur crache des choses qui correspondent à cela. Y at-il quelque chose là-bas déjà cuit que je peux utiliser pour faire cela? Ou y a-t-il une bibliothèque qui m'amène le plus loin?Utilisation de Regex pour générer des chaînes plutôt que de les faire correspondre

Merci

+0

Voici une [bibliothèque java] utile (https://github.com/mifmif/Generex) qui fournit de nombreuses fonctionnalités pour utiliser regex pour générer de la chaîne (génération aléatoire, générer une chaîne en fonction de son index, générer toute la chaîne ..) vérifier out [ici] (https://github.com/mifmif/Generex) – Mifmif

Répondre

30

Edit:

Comme mentionné dans les commentaires, il y a une bibliothèque disponible sur Google Code acheive ceci: http://code.google.com/p/xeger

Voir aussi https://github.com/mifmif/Generex comme suggéré par Mifmif

Message original :

Premièrement, wit h un complexe assez complexe, je crois que cela peut être impossible. Mais vous devriez être capable de mettre quelque chose ensemble pour des expressions rationnelles simples.

Si vous regardez le code source de la classe java.util.regex.Pattern, vous verrez qu'il utilise une représentation interne des instances de nœud. Chacun des composants de modèle différents ont leur propre implémentation d'une sous-classe Node. Ces nœuds sont organisés en arbre. En produisant un visiteur qui traverse cet arbre, vous devriez être capable d'appeler une méthode de générateur surchargée ou une sorte de Builder qui bricole quelque chose ensemble.

+4

Actuellement, il existe une bibliothèque Java: http://code.google.com/p/xeger/ –

+0

Je ne suis pas sûr que Xeger soit aussi bon. Il ne peut pas gérer les classes de caractères. Il ne parvient pas à reconnaître un simple [\ w] '. Un coup d'œil à la dernière ligne de [leur wiki] (https://code.google.com/archive/p/xeger/wikis/XegerLimitations.wiki) nous le dit. Le lien –

1

Vous devez écrire votre propre analyseur, comme l'auteur de cordes :: aléatoire (Perl) fait. En fait, il n'utilise pas les regex dans ce module, c'est juste ce à quoi les perl-coders sont habitués. D'autre part, peut-être vous pouvez jeter un oeil à the source, pour obtenir quelques pointeurs.


EDIT: Bon sang, blair m'a battu au coup de poing de 15 secondes.

4

Visual Studio Team System inclut quelque chose comme ceci. Check it out

Pas beaucoup d'aide pour Java, donc désolé.

3

Le podcast stackoverflow 11:

Spolsky: Ouais. Il y a aussi un nouveau produit, si vous ne voulez pas utiliser le système d'équipe, nos amis chez Redgate ont un produit appelé SQL Data Generator [http://www.red-gate.com/products/sql_data_generator/index.htm]]. C'est 295 $, et cela génère juste des données de test réalistes. Et ça fait des choses comme générer des villes réelles dans la colonne de la ville qui existent réellement, et puis quand ça les génère, ça va faire l'Etat, au lieu d'avoir mal l'état, ou mettre des états dans des villes allemandes et des choses comme ... Vous savez, cela génère des données d'apparence assez réaliste. Je ne suis pas vraiment sûr de ce que toutes les fonctionnalités sont.

Ce n'est probablement pas ce que vous cherchez, mais c'est peut-être un bon point de départ, au lieu de créer le vôtre.Comme je n'arrive pas à trouver quoi que ce soit dans google, je suggère de résoudre le problème en analysant une expression régulière donnée dans les plus petites unités de travail (\ w, [xx], \ d, etc.) et en écrivant méthodes de base pour soutenir ces expressions d'expression régulières. Donc, pour \ w vous auriez une méthode getRandomLetter() qui retourne une lettre aléatoire, et vous auriez aussi getRandomLetter (char startLetter, char endLetter) qui vous donne une lettre au hasard entre les deux valeurs.

2

Je sais qu'il y a déjà une réponse acceptée, mais j'ai utilisé Data Generator de RedGate (celui mentionné dans la réponse de Craig) et cela fonctionne vraiment bien pour tout ce que j'ai jeté. C'est rapide et cela me laisse envie d'utiliser la même expression pour générer les données réelles pour des choses comme les codes d'enregistrement que cette chose crache.

Il faut regex comme:

[A-Z0-9]{3,3}-[A-Z0-9]{3,3} 

et il génère des tonnes de codes uniques comme:

LLK-32U 

Est-ce un grand algorithme secret que Redgate a compris et nous sommes tous sur chance ou est-ce quelque chose que nous, simples mortels, pourrions réellement faire?

0

Il est loin de prendre en charge une expression rationnelle PCRE complète, mais j'ai écrit la méthode Ruby suivante pour prendre une chaîne de type expression rationnelle et produire une variation sur celle-ci. (Pour CAPTCHA fondée sur la langue.)

# q = "(How (much|many)|What) is (the (value|result) of)? :num1 :op :num2?" 
# values = { :num1=>42, :op=>"plus", :num2=>17 } 
# 4.times{ puts q.variation(values) } 
# => What is 42 plus 17? 
# => How many is the result of 42 plus 17? 
# => What is the result of 42 plus 17? 
# => How much is the value of 42 plus 17? 
class String 
    def variation(values={}) 
    out = self.dup 
    while out.gsub!(/\(([^())?]+)\)(\?)?/){ 
     ($2 && (rand > 0.5)) ? '' : $1.split('|').random 
    }; end 
    out.gsub!(/:(#{values.keys.join('|')})\b/){ values[$1.intern] } 
    out.gsub!(/\s{2,}/, ' ') 
    out 
    end 
end 

class Array 
    def random 
    self[ rand(self.length) ] 
    end 
end
4

Je suis allé la racine de rouler ma bibliothèque own pour cela (en C#, mais devrait être facile à comprendre pour un développeur Java). Rxrdg a commencé comme une solution à un problème de création de données de test pour un projet réel. L'idée de base est de tirer parti des modèles de validation existants (expression régulière) pour créer des données aléatoires conformes à ces modèles. De cette façon, des données aléatoires valides sont créées.

Il n'est pas si difficile d'écrire un analyseur pour des motifs regex simples. L'utilisation d'un arbre de syntaxe abstraite pour générer des chaînes devrait être encore plus facile.

+0

ne pointe plus vers le référentiel. J'irais avec https://www.openhub.net/p/rxrdg. La solution ne construit pas, cependant? – Veverke

18

Xeger (Java) est capable de le faire ainsi:

String regex = "[ab]{4,6}c"; 
Xeger generator = new Xeger(regex); 
String result = generator.generate(); 
assert result.matches(regex); 
+1

Xeger fonctionne bien. MAIS assurez-vous que vous avez le [pot d'automate] (https://mvnrepository.com/artifact/dk.brics.automaton/automaton/1.11-8) sur le chemin de la classe ou dans votre pom/gradle –

1

Je suis sur le vol et juste vu la question: je l'ai écrit plus facile, mais la solution inefficace et incomplète. J'espère que cela peut vous aider à commencer à écrire votre propre analyseur:

public static void main(String[] args) { 

    String line = "[A-Z0-9]{16}"; 
    String[] tokens = line.split(line); 
    char[] pattern = new char[100]; 
    int i = 0; 
    int len = tokens.length; 
    String sep1 = "[{"; 
    StringTokenizer st = new StringTokenizer(line, sep1); 

    while (st.hasMoreTokens()) { 
     String token = st.nextToken(); 
     System.out.println(token); 

     if (token.contains("]")) { 
      char[] endStr = null; 

      if (!token.endsWith("]")) { 
       String[] subTokens = token.split("]"); 
       token = subTokens[0]; 

       if (!subTokens[1].equalsIgnoreCase("*")) { 
        endStr = subTokens[1].toCharArray(); 
       } 
      } 

      if (token.startsWith("^")) { 
       String subStr = token.substring(1, token.length() - 1); 
       char[] subChar = subStr.toCharArray(); 
       Set set = new HashSet<Character>(); 

       for (int p = 0; p < subChar.length; p++) { 
        set.add(subChar[p]); 
       } 

       int asci = 1; 

       while (true) { 
        char newChar = (char) (subChar[0] + (asci++)); 

        if (!set.contains(newChar)) { 
         pattern[i++] = newChar; 
         break; 
        } 
       } 
       if (endStr != null) { 
        for (int r = 0; r < endStr.length; r++) { 
         pattern[i++] = endStr[r]; 
        } 
       } 

      } else { 
       pattern[i++] = token.charAt(0); 
      } 
     } else if (token.contains("}")) { 
      char[] endStr = null; 

      if (!token.endsWith("}")) { 
       String[] subTokens = token.split("}"); 
       token = subTokens[0]; 

       if (!subTokens[1].equalsIgnoreCase("*")) { 
        endStr = subTokens[1].toCharArray(); 
       } 
      } 

      int length = Integer.parseInt((new StringTokenizer(token, (",}"))).nextToken()); 
      char element = pattern[i - 1]; 

      for (int j = 0; j < length - 1; j++) { 
       pattern[i++] = element; 
      } 

      if (endStr != null) { 
       for (int r = 0; r < endStr.length; r++) { 
        pattern[i++] = endStr[r]; 
       } 
      } 
     } else { 
      char[] temp = token.toCharArray(); 

      for (int q = 0; q < temp.length; q++) { 
       pattern[i++] = temp[q]; 
      } 
     } 
    } 

    String result = ""; 

    for (int j = 0; j < i; j++) { 
     result += pattern[j]; 
    } 

    System.out.print(result); 
} 
+0

Vous pouvez indiquer quel genre de chaînes sont utilisées comme entrée de modèle. Tout d'abord, il n'est pas si simple de déterminer de telles choses à partir du code source. Deuxièmement, s'il y a des erreurs ou des erreurs dans le code source, il n'y a aucun moyen de voir si elles sont intentionnelles ou non. –

+0

StringTokenizer est une classe héritée qui est conservée pour des raisons de compatibilité bien que son utilisation soit déconseillée dans le nouveau code. Il est recommandé que toute personne recherchant cette fonctionnalité utilise à la place la méthode split de String ou le package java.util.regex. – Rohit

10

Il est trop tard pour aider l'affiche originale, mais elle peut aider un nouveau venu. Generex est une bibliothèque java utile qui fournit de nombreuses fonctionnalités pour utiliser les regexes pour générer des chaînes (génération aléatoire, génération d'une chaîne basée sur son index, génération de toutes les chaînes ...).

Exemple:

Generex generex = new Generex("[0-3]([a-c]|[e-g]{1,2})"); 

// generate the second String in lexicographical order that matches the given Regex. 
String secondString = generex.getMatchedString(2); 
System.out.println(secondString);// it print '0b' 

// Generate all String that matches the given Regex. 
List<String> matchedStrs = generex.getAllMatchedStrings(); 

// Using Generex iterator 
Iterator iterator = generex.iterator(); 
while (iterator.hasNext()) { 
    System.out.print(iterator.next() + " "); 
} 
// it prints 0a 0b 0c 0e 0ee 0e 0e 0f 0fe 0f 0f 0g 0ge 0g 0g 1a 1b 1c 1e 
// 1ee 1e 1e 1f 1fe 1f 1f 1g 1ge 1g 1g 2a 2b 2c 2e 2ee 2e 2e 2f 2fe 2f 2f 2g 
// 2ge 2g 2g 3a 3b 3c 3e 3ee 3e 3e 3f 3fe 3f 3f 3g 3ge 3g 3g 1ee 

// Generate random String 
String randomStr = generex.random(); 
System.out.println(randomStr);// a random value from the previous String list 
+5

On dirait que Generex est votre propre projet. Pourriez-vous mentionner dans votre message que c'est votre propre projet, conformément aux règles [ici] (http://stackoverflow.com/help/behavior)? –

-1

Si vous voulez générer des chaînes "critiques", vous pouvez envisager:

EGRET http://elarson.pythonanywhere.com/ qui génère des chaînes "mauvaises" couvrant vos expressions régulières

MUTREX http://cs.unibg.it/mutrex/ qui génère des chaînes de détection d'erreur par mutation regex

Les deux sont des outils académiques (je suis l'un des auteurs de ce dernier) et fonctionnent raisonnablement bien.

-1

Cette question est très ancienne, mais je suis tombé dessus lors de ma propre recherche, donc je vais inclure quelques liens pour d'autres personnes qui pourraient rechercher la même fonctionnalité dans d'autres langues.

Questions connexes