Utiliser Regex pour générer des chaînes plutôt que de les faire correspondre

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 de pouvoir spécifier une regex pour Ssortingngs afin que mon générateur crache des choses qui correspondent à cela. Y a-t-il quelque chose de déjà cuit que je peux utiliser pour le faire? Ou y a-t-il une bibliothèque qui me mène le plus loin possible?

Merci

Modifier:

Comme mentionné dans les commentaires, une bibliothèque est disponible sur Google Code pour cela: http://code.google.com/p/xeger

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

Message original:

Premièrement, avec une expression rationnelle assez complexe, je pense que cela peut être impossible. Mais vous devriez pouvoir mettre quelque chose ensemble pour des expressions rationnelles simples.

Si vous examinez le code source de la classe java.util.regex.Pattern, vous verrez qu’il utilise une représentation interne des instances de noeud. Chacun des différents composants de modèle a sa propre implémentation d’une sous-classe de nœud. Ces nœuds sont organisés dans un arbre.

En produisant un visiteur qui traverse cet arbre, vous devriez pouvoir appeler une méthode de générateur surchargée ou une sorte de générateur qui bricole quelque chose.

Xeger (Java) est également capable de le faire:

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

Il est trop tard pour aider l’affiche originale, mais cela pourrait aider un nouveau venu. Generex est une bibliothèque Java utile qui fournit de nombreuses fonctionnalités pour utiliser des expressions rationnelles 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érant toutes les chaînes …).

Exemple :

 Generex generex = new Generex("[0-3]([ac]|[eg]{1,2})"); // generate the second Ssortingng in lexicographical order that matches the given Regex. Ssortingng secondSsortingng = generex.getMatchedSsortingng(2); System.out.println(secondSsortingng);// it print '0b' // Generate all Ssortingng that matches the given Regex. List matchedStrs = generex.getAllMatchedSsortingngs(); // 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 Ssortingng Ssortingng randomStr = generex.random(); System.out.println(randomStr);// a random value from the previous Ssortingng list 

Je suis allé à la racine de ma propre bibliothèque pour cela (dans c # mais devrait être facile à comprendre pour un développeur Java).

Rxrdg a commencé comme 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 parsingur syntaxique simple pour des motifs de regex simples. L’utilisation d’un arbre de syntaxe abstrait pour générer des chaînes devrait être encore plus simple.

Visual Studio Team System inclut quelque chose comme ça. Vérifiez-le

Pas grand chose pour Java, désolé.

Sur le podcast stackoverflow 11:

Spolsky: Ouais. Il y a aussi un nouveau produit, si vous ne voulez pas utiliser le Team System, nos amis de Redgate ont un produit appelé SQL Data Generator [ http://www.red-gate.com/products/sql_data_generator/index.htm%5D. . C’est 295 $, et cela ne fait que générer des données de test réalistes. Et des choses comme générer réellement de véritables villes dans la colonne de la ville qui existent réellement, puis quand elles les génèrent, l’État aura raison, au lieu de se tromper ou de mettre des États dans des villes allemandes et des choses comme … vous savez, cela génère des données d’aspect assez réaliste. Je ne suis pas vraiment sûr de toutes les fonctionnalités.

Ce n’est probablement pas ce que vous recherchez, mais cela pourrait être un bon sharepoint départ, au lieu de créer le vôtre.

Je n’arrive pas à trouver quoi que ce soit dans Google. Je suggère donc d’aborder 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 quelques méthodes de base pour supporter ces phrases d’expression régulière.

Donc, pour \ w, vous auriez une méthode getRandomLetter () qui renvoie n’importe quelle lettre aléatoire et vous auriez également getRandomLetter (char startLetter, char endLetter) qui vous donne une lettre aléatoire entre les deux valeurs.

Je sais qu’il y a déjà une réponse acceptée, mais j’utilise le générateur de données de RedGate (celui mentionné dans la réponse de Craig) et ça marche vraiment bien pour tout ce que je lui ai lancé. C’est rapide et cela me laisse envie d’utiliser la même regex pour générer les données réelles pour des choses comme les codes d’enregistrement que cette chose crache.

Il faut une 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 que c’est un gros algorithme secret que RedGate a compris et nous avons tous perdu la chance ou est-ce quelque chose que nous, simples mortels, pouvons réellement faire?

Je suis en vol et je viens de voir la question: j’ai écrit une solution plus simple mais inefficace et incomplète. J’espère que cela pourrait vous aider à écrire votre propre parsingur syntaxique:

 public static void main(Ssortingng[] args) { Ssortingng line = "[A-Z0-9]{16}"; Ssortingng[] tokens = line.split(line); char[] pattern = new char[100]; int i = 0; int len = tokens.length; Ssortingng sep1 = "[{"; SsortingngTokenizer st = new SsortingngTokenizer(line, sep1); while (st.hasMoreTokens()) { Ssortingng token = st.nextToken(); System.out.println(token); if (token.contains("]")) { char[] endStr = null; if (!token.endsWith("]")) { Ssortingng[] subTokens = token.split("]"); token = subTokens[0]; if (!subTokens[1].equalsIgnoreCase("*")) { endStr = subTokens[1].toCharArray(); } } if (token.startsWith("^")) { Ssortingng subStr = token.subssortingng(1, token.length() - 1); char[] subChar = subStr.toCharArray(); Set set = new HashSet(); 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); } 

Vous devrez écrire votre propre parsingur, comme l’auteur de Ssortingng :: Random (Perl). En fait, il n’utilise aucune expression régulière dans ce module, c’est juste ce à quoi les codeurs Perl sont habitués.

D’un autre côté, vous pouvez peut-être jeter un coup d’œil à la source pour obtenir des indications.


EDIT: Merde, blair m’a battu au poing par 15 secondes.

C’est loin de supporter une expression rationnelle complète de PCRE, mais j’ai écrit la méthode Ruby suivante pour prendre une chaîne de type regexp et en faire une variante. (Pour CAPTCHA basé 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 Ssortingng 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 

Si vous souhaitez générer des chaînes “critiques”, vous pouvez envisager:

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

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

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

Cette question est très ancienne, mais je suis tombée dessus par hasard lors de ma propre recherche. Je vais donc inclure quelques liens vers d’autres personnes qui pourraient chercher la même fonctionnalité dans d’autres langues.