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

StackOverflow https://stackoverflow.com/questions/22115

  •  09-06-2019
  •  | 
  •  

Question

J'écris un utilitaire Java qui m'aide à générer de nombreuses données pour les tests de performances.Ce serait vraiment c'est cool de pouvoir spécifier une expression régulière pour les chaînes afin que mon générateur crache des choses qui correspondent à cela.Existe-t-il quelque chose de déjà préparé que je peux utiliser pour faire cela ?Ou existe-t-il une bibliothèque qui me permet d'y parvenir la plupart du temps ?

Merci

Était-ce utile?

La solution

Modifier:

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

Voir également https://github.com/mifmif/Generex comme le suggère Mifmif

Message d'origine :

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

Si vous jetez un œil au code source de la classe java.util.regex.Pattern, vous verrez qu'elle utilise une représentation interne des instances de Node.Chacun des différents composants du modèle a sa propre implémentation d'une sous-classe Node.Ces nœuds sont organisés en arborescence.

En produisant un visiteur qui traverse cette arborescence, vous devriez pouvoir appeler une méthode génératrice surchargée ou une sorte de Builder qui bricole quelque chose.

Autres conseils

Xeger (Java) est capable de le faire aussi :

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

Il est trop tard pour aider l'affiche originale, mais cela pourrait aider un nouveau venu. Générex est une bibliothèque Java utile qui fournit de nombreuses fonctionnalités pour utiliser des expressions régulières 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

J'ai commencé à rouler mon propre bibliothèque 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 d'exploiter les 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 modèles d'expression régulière simples.Utiliser un arbre de syntaxe abstraite pour générer des chaînes devrait être encore plus simple.

Sur le podcast stackoverflow 11 :

Spolski :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].C'est 295 $ et cela génère simplement des données de test réalistes.Et il fait des choses comme générer de vraies villes dans la colonne des villes qui existent réellement, et ensuite, quand il les génère, il donne raison à l'État, au lieu de se tromper d'État, ou de placer des États dans des villes allemandes et des trucs comme...vous savez, cela génère des données assez réalistes.Je ne suis pas vraiment sûr de quelles sont toutes les fonctionnalités.

Ce n'est probablement pas ce que vous recherchez, mais cela pourrait être un bon point de 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 de résoudre le problème en analysant une expression régulière donnée dans les plus petites unités de travail (\w, [x-x], \d, etc.) et en écrivant quelques méthodes de base pour prendre en charge ces expressions régulières.

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 existe déjà une réponse acceptée, mais j'utilise Générateur de données de RedGate (celui mentionné dans la réponse de Craig) et cela fonctionne VRAIMENT bien pour tout ce que je lui ai lancé.C'est rapide et cela me donne envie d'utiliser la même expression régulière 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

S'agit-il d'un algorithme secret que RedGate a découvert et nous n'avons pas de chance ou est-ce quelque chose que nous, simples mortels, pourrions réellement faire ?

Je suis en vol et je viens de voir la question :J'ai écrit la solution la plus simple mais inefficace et incomplète.J'espère que cela pourra 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);
}

Vous devrez écrire votre propre analyseur, comme l'a fait l'auteur de String::Random (Perl).En fait, il n'utilise d'expressions régulières nulle part dans ce module, c'est simplement ce à quoi les codeurs Perl sont habitués.

D'un autre côté, tu peux peut-être jeter un oeil à la source, pour avoir quelques indications.


MODIFIER:Merde, Blair m'a devancé de 15 secondes.

C'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 en produire une variation.(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 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

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

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

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

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

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top