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. Il serait vraiment cool de pouvoir spécifier un regex pour les chaînes de sorte que mon générateur crache des choses qui correspondent à cela. Y a-t-il quelque chose que j'utilise pour faire ça? Ou y a-t-il une bibliothèque qui m'attire le plus?

Merci

90
demandé sur Andrew Harmel-Law 2008-08-22 15:35:41

11 réponses

Edit:

comme mentionné dans les commentaires, Il ya une bibliothèque disponible à Google Code pour atteindre ce: http://code.google.com/p/xeger

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

message Original:

tout D'abord, avec un assez complexe regexp, je crois que cela peut être impossible. Mais vous devriez pouvoir assembler quelque chose pour de simples regexps.

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 noeuds. Chacun des différents composants de modèle ont leur propre mise en œuvre d'une sous-classe de Noeud. Ces Nœuds sont organisés dans un arbre.

en produisant un visiteur qui traverse cet arbre, vous devrait être capable d'appeler une méthode de générateur surchargé ou une sorte de constructeur qui bricole quelque chose ensemble.

31
répondu Cheekysoft 2017-05-23 10:31:14

Xeger (Java) est capable de le faire aussi bien:

String regex = "[ab]{4,6}c";
Xeger generator = new Xeger(regex);
String result = generator.generate();
assert result.matches(regex);
18
répondu Wilfred Springer 2016-09-06 22:08:42

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 l'utilisation de 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
14
répondu Mifmif 2016-06-02 22:08:55

je suis allé à la racine de 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 d'essai pour un projet de la vie réelle. 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 qui se conforment à de tels modèles. De cette façon, des données aléatoires valides sont créées.

Ce n'est pas que difficile d'écrire un analyseur pour des motifs regex simples. Utiliser une arborescence de syntaxe abstraite pour générer des chaînes devrait être encore plus facile.

4
répondu Goran 2015-09-04 06:56:16

On stackoverflow podcast 11:

Spolsky: Yep. Il y a aussi un nouveau produit, si vous ne voulez pas utiliser le système D'équipe là-bas nos amis à Redgate ont un produit appelé Générateur de données SQL [ http://www.red-gate.com/products/sql_data_generator/index.htm] . C'est 295$, et ça génère juste des données de test réalistes. Et ça fait des choses comme générer de vraies villes dans la colonne des villes qui existent réellement, et puis quand il génère ceux-ci, il aura le droit d'état, au lieu de se tromper d'état, ou de mettre des États dans les villes allemandes et des trucs du genre... vous savez, il génère assez réaliste à la recherche de données. Je ne suis pas vraiment sûr de ce que sont toutes les fonctionnalités.

Ce n'est probablement pas ce que vous cherchez, mais il pourrait être un bon point de départ, au lieu de créer votre propre.

Je ne trouve rien dans google, donc je suggère s'attaquer au 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 supporter 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 aussi getRandomLetter(char startLetter, char endLetter) qui vous donne une lettre aléatoire entre les deux valeurs.

3
répondu Craig 2008-08-22 12:07:55

je sais qu'il y a déjà une réponse acceptée, mais j'ai utilisé 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 ça me laisse envie d'utiliser le même regex pour générer les vraies données 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 d'unique codes comme:

LLK-32U

est-ce 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 faire?

2
répondu J Wynia 2011-11-24 08:13:17

je suis en vol et je viens de voir la question: j'ai écrit la solution la plus facile mais inefficace et incomplète. J'espère que cela vous aidera à 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);
}
2
répondu R dhabalia 2012-09-27 22:07:58

vous devrez écrire votre propre analyseur, comme L'a fait l'auteur de String::Random (Perl). En fait, il n'utilise pas de regexes dans ce module, c'est juste ce à quoi les codes perl sont habitués.

d'un autre côté, peut-être que vous pouvez jeter un oeil à la source , pour obtenir quelques pointeurs.


EDIT: Merde, blair me battre pour le punch en 15 secondes.

1
répondu Espo 2008-10-09 13:33:31

c'est loin de supporter un regexp PCRE complet, mais j'ai écrit la méthode Ruby suivante pour prendre une chaîne de type regexp 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!( /\(([^())?]+)\)(\?)?/ ){
      (  && ( rand > 0.5 ) ) ? '' : .split( '|' ).random
    }; end
    out.gsub!( /:(#{values.keys.join('|')})\b/ ){ values[.intern] }
    out.gsub!( /\s{2,}/, ' ' )
    out
  end
end

class Array
  def random
    self[ rand( self.length ) ]
  end
end
0
répondu 2008-11-11 05:31:33

si vous voulez générer des chaînes "critiques", vous pouvez considérer:

EGRET http://elarson.pythonanywhere.com / qui génère des cordes "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

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

-1
répondu Angelo Gargantini 2017-03-16 03:10:48

cette question est très ancienne, mais je suis tombé sur elle sur ma propre recherche, donc je vais inclure quelques liens pour d'autres qui pourraient être à la recherche de la même fonctionnalité dans d'autres langues.

-1
répondu Everett 2017-07-17 02:07:29