web-dev-qa-db-fra.com

Étant donné une chaîne, générer une expression rationnelle pouvant analyser * chaînes * similaires

Par exemple, étant donné la chaîne "2009/11/12", je veux obtenir l'expression régulière ("\ d {2}/d {2}/d {4}"), je vais donc pouvoir faire correspondre "2001/01/02 "aussi.

Y a-t-il quelque chose qui fait ça? Quelque chose de similaire? Une idée sur la façon de le faire?

25
Yossale

Il existe text2re , un générateur gratuit de "regex by example" basé sur le Web.

Je ne pense pas que cela soit disponible dans le code source, cependant. J'ose dire qu'il n'y a pas de générateur de regex automatique qui fonctionne correctement sans intervention de l'utilisateur, car cela demanderait à la machine de savoir ce que vous voulez.


Notez que text2re utilise une approche de la génération d’expression régulière, généralisée et très généralisée, basée sur des modèles. Les expressions qu’il génère fonctionnent, mais elles sont beaucoup plus complexes que les expressions équivalentes fabriquées à la main. Ce n'est pas un bon outil pour apprendre les expressions régulières, car il fait un travail assez moche pour donner des exemples.

Par exemple, la chaîne "2009/11/12" serait reconnue comme un motif yyyymmdd, ce qui est utile. L'outil le transforme en ce monstre de 125 caractères:

((?:(?:[1]{1}\d{1}\d{1}\d{1})|(?:[2]{1}\d{3}))[-:\/.](?:[0]?[1-9]|[1][012])[-:\/.](?:(?:[0-2]?\d{1})|(?:[3][01]{1})))(?![\d])

L'équivalent fabriqué à la main ne prendrait que les deux cinquièmes de celui-ci (50 caractères):

([12]\d{3})[-:/.](0?\d|1[0-2])[-:/.]([0-2]?\d|3[01])\b
25
Tomalak

Il n'est pas possible d'écrire une solution générale à votre problème. Le problème est que tout générateur ne saurait probablement pas ce que vous voulez vérifier, par exemple. "2312/45/67" devrait-il également être autorisé? Qu'en est-il de "2009.11.12"?

Ce que vous pouvez faire est d’écrire vous-même un tel générateur qui convient parfaitement à votre problème, mais une solution générale ne sera pas possible.

11
B.E.

Excusez-moi, mais ce que vous appelez tous impossible est clairement une tâche réalisable. Il ne sera pas en mesure de donner des résultats pour TOUS les exemples, et peut-être pas les meilleurs, mais vous pouvez lui donner divers indices et cela facilitera la vie. Quelques exemples suivront.

Une sortie lisible traduisant le résultat serait également très utile. Quelque chose comme: 

  • "Rechercher: un mot commençant par une lettre non numérique et finissant par la chaîne" ing ".
  • ou: Rechercher: texte contenant bbb, suivi quelque part par zzz
  • ou: * Rechercher: un motif qui a l'air si "aa/bbbb/cccc" où "/" est un séparateur, "aa" est deux chiffres, "bbbb" est un mot de n'importe quelle longueur et "cccc" sont quatre chiffres entre 1900 et 2020 *

Peut-être pourrions-nous créer un "traducteur arrière" avec un langage de type SQL pour créer un regex, au lieu de le créer en geekish.

Voici quelques exemples faisables: 

class Hint: 
  Properties: HintType, HintString
  enum HintType { Separator, ParamDescription, NumberOfParameters }
  enum SampleType { FreeText, DateOrTime, Formatted, ... }
  public string RegexBySamples( List<T> samples, 
         List<SampleType> sampleTypes, 
         List<Hint> hints, 
         out string GeneralRegExp, out string description, 
         out string generalDescription)...

regex = RegExpBySamples( {"11/November/1999", "2/January/2003"}, 
                     SampleType.DateOrTime, 
                     new HintList( HintType.NumberOfParameters, 3 ));

regex = RegExpBySamples( "123-aaaaJ-1444", 
                         SampleType.Format, HintType.Seperator, "-" );

Une interface graphique où vous marquez un texte ou le saisissez, l'ajout à l'expression régulière serait également possible. Tout d’abord, vous marquez une date ("échantillon") et choisissez si ce texte est déjà formaté ou si vous construisez un format, ainsi que le type de format: texte libre, texte formaté, date, GUID ou Choisir ... parmi les formats existants (que vous pouvez stocker dans la bibliothèque).

Permet de concevoir une spécification pour cela, et de le rendre open source ... Quelqu'un veut-il rejoindre?

4
pashute

J'ai essayé une approche très naïve:

class RegexpGenerator {

    public static Pattern generateRegexp(String prototype) {
        return Pattern.compile(generateRegexpFrom(prototype));
    }

    private static String generateRegexpFrom(String prototype) {
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < prototype.length(); i++) {
            char c = prototype.charAt(i);

            if (Character.isDigit(c)) {
                stringBuilder.append("\\d");
            } else if (Character.isLetter(c)) {
                stringBuilder.append("\\w");
            } else { // falltrought: literal
                stringBuilder.append(c);
            }
        }

        return stringBuilder.toString();
    }

    private static void test(String prototype) {
        Pattern pattern = generateRegexp(prototype);
        System.out.println(String.format("%s -> %s", prototype, pattern));

        if (!pattern.matcher(prototype).matches()) {
            throw new AssertionError();
        }
    }

    public static void main(String[] args) {
        String[] prototypes = {
            "2009/11/12",
            "I'm a test",
            "me too!!!",
            "124.323.232.112",
            "ISBN 332212"
        };

        for (String prototype : prototypes) {
            test(prototype);
        }
    }
}

sortie:

2009/11/12 ->\d\d\d\d/\ d\d/\ d\d
Je suis un test ->\w '\ w\w\w\w\w\w
moi aussi!!! ->\w\w\w\w\w !!!
124.323.232.112 ->\d\d\d.\D\d\d.\D\d\d.\D\d\d\d
ISBN 332212 ->\w\w\w\w\d\d\d\d\d\d\d

Comme déjà souligné par d'autres, une solution générale à ce problème est impossible. Cette classe est applicable uniquement dans quelques contextes 

3
dfa

cela ressemble à un problème d’apprentissage automatique. Vous devrez disposer de plus d'un exemple (beaucoup plus) et indiquer si chaque exemple est considéré comme une correspondance ou non.

1
Kyle Dyer

Non, vous ne pouvez pas obtenir une expression régulière qui corresponde à ce que vous voulez, car elle ne contiendrait pas d’informations sémantiques sur l’entrée (c’est-à-dire qu’elle aurait besoin de savoir qu’elle génère une expression régulière pour les dates). Si le problème concerne uniquement les dates, je vous recommanderais d'essayer plusieurs expressions régulières et de voir si l'une d'elles correspond à toutes.

1
soulmerge

Je ne sais pas si cela est possible, du moins pas sans exemples de chaînes et d'algorithmes d'apprentissage. 

Il y a beaucoup de regex 'qui correspondraient et il n'est pas possible pour un simple algorithme de choisir le' bon '. Vous devez lui donner des délimiteurs ou d'autres éléments à rechercher, vous pouvez donc aussi bien écrire vous-même la regex.

1
Cogsy

Loreto fait à peu près cela. C'est une implémentation open source utilisant la plus longue sous-chaîne commune pour générer les expressions régulières. A besoin de plusieurs exemples de cours, cependant.

1
Tyberius Prime

En plus de fournir à l'algorithme d'apprentissage des exemples de "bonne" entrée, vous pouvez le nourrir "mauvais" afin qu'il sache quoi ne pas rechercher. Aucune lettre dans un numéro de téléphone, par exemple.

0
JDrago

Je ne me souviens pas du nom mais si ma théorie du calcul des cellules me sert correctement, c'est impossible en théorie :)

0
MahdeTo

Je n'ai rien trouvé qui puisse le faire, mais puisque le domaine du problème est relativement petit (vous seriez surpris de voir combien de personnes utilisent les formats de date les plus étranges), j'ai pu écrire une sorte de "date" générateur d'expression régulière ". Une fois que je serai satisfait des tests unitaires, je le publierai, au cas où quelqu'un aurait besoin de quelque chose du genre.

Merci à tous ceux qui ont répondu (le gars avec le (. *) Exclus - les blagues sont géniales, mais celui-ci était sssssssssoooo boiteux :))

0
Yossale