2009-04-22 15 views
25

Ad esempio, data la stringa "2009/11/12" Voglio ottenere l'espressione regolare ("\ d {2}/d {2}/d {4} "), quindi potrò abbinare anche" 2001/01/02 ".Data una stringa, generare una espressione regolare che può analizzare * stringhe simili *

C'è qualcosa che lo fa? Qualcosa di simile? Qualche idea su come fare?

+0

Possibile duplicato di [È possibile che un computer "impari" un'espressione regolare con esempi forniti dall'utente?] (Https://stackoverflow.com/questions/616292/is-it-possible-for-a- computer-to-learn-a-regular-expression-by-user-provided-e) –

risposta

23

C'è text2re, un free web-based "regex con l'esempio" generatore.

Non penso che questo sia disponibile nel codice sorgente, però. Oserei dire che non esiste un generatore di regex automatico che funzioni correttamente senza l'intervento dell'utente, poiché ciò richiederebbe alla macchina la conoscenza di ciò che si desidera.


Si noti che text2re utilizza un approccio basato su modelli, modularizzato e molto generalizzato alla generazione di espressioni regolari. Le espressioni che genera funzionano, ma sono molto più complesse rispetto all'espressione equivalente realizzata a mano. Non è un buon strumento per imparare le espressioni regolari perché fa un lavoro piuttosto schifoso agli esempi di impostazione.

Ad esempio, la stringa "2009/11/12" viene riconosciuta come uno schema yyyymmdd, che è utile. Lo strumento trasforma in questo mostro 125 carattere:

((?:(?:[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'equivalente artigianale occuperebbe soltanto due quinti di quella (50 caratteri):

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

Non è possibile scrivere una soluzione generale per il problema. Il problema è che probabilmente qualsiasi generatore non saprebbe cosa si desidera controllare, ad es. dovrebbe essere permesso anche "2312/45/67"? Che dire di "2009.11.12"?

Quello che potresti fare è scrivere un generatore di questo tipo che sia adatto al tuo problema esatto, ma una soluzione generale non sarà possibile.

1

No, non è possibile ottenere un'espressione regolare che corrisponda a ciò che si desidera in modo affidabile, poiché l'espressione regolare non conterrà informazioni semantiche sull'input (ossia, sarebbe necessario sapere che sta generando un'espressione regolare per le date). Se il problema riguarda solo le date, consiglierei di provare più espressioni regolari e vedere se una di esse corrisponde a tutte.

1

Non sono sicuro se questo è possibile, almeno non senza molte stringhe di esempio e qualche algoritmo di apprendimento.

Ci sono molte espressioni regolari che corrispondono e non è possibile che un semplice algoritmo scelga quello "giusto". Dovresti dargli dei delimitatori o altre cose da cercare, quindi potresti anche scrivere la regex da solo.

0

non ricordo il nome, ma se la mia teoria delle cellule di calcolo servire me proprio la sua impossibilità in teoria :)

3

ho provato molto approccio ingenuo:

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); 
     } 
    } 
} 

uscita:

2009/11/12 -> \ d \ d \ d \ d/\ d \ \/\ d \ d
Sono un test -> \ w '\ w \ w \ w \ w \ w \ w
anch'io !!! -> \ w \ w \ w \ w \ w !!!
124.323.232.112 -> \ d \ d \ d. \ D \ d \ d. \ D \ d \ d. \ D \ d \ d
ISBN 332212 -> \ w \ w \ w \ w \ d \ d \ \ \ \ \ \ \ d

Come già delineato da altri, una soluzione generale a questo problema è impossibile. Questa classe è applicabile solo in alcuni contesti

1

suona come un problema di apprendimento automatico. Dovrai avere più di un esempio a disposizione (molti altri) e un'indicazione se ogni esempio è considerato o meno un match.

+0

In particolare, si tratta di un problema [induzione grammaticale] (https://en.wikipedia.org/wiki/Grammar_induction). –

0

Non ho trovato nulla che lo faccia, ma poiché il dominio del problema è relativamente piccolo (sarete sorpresi da quante persone usano i formati di data più strani), ho potuto scrivere una specie di "data generatore di espressioni regolari". Una volta che sarò soddisfatto dei test unitari, lo pubblicherò - nel caso qualcuno abbia mai bisogno di qualcosa del genere.

Grazie a tutti coloro che hanno risposto (. Il ragazzo con il (*) esclusi - scherzi sono grandi, ma questo era sssssssssoooo zoppo :))

3

Mi scusi, ma quello che tutte le chiamate impossibile è chiaramente un realizzabili compito. Non sarà in grado di dare risultati per TUTTI gli esempi, e forse non i risultati migliori, ma puoi dargli vari suggerimenti e renderà la vita facile. Seguiranno alcuni esempi.

Anche un'uscita leggibile che traduca il risultato sarebbe molto utile. Qualcosa di simile:

  • "Cerca: una parola che inizia con una lettera non numerico e termina con la stringa: 'Ing.'
  • o: Cerca: testo che ha bbb in esso , seguito da qualche parte da zzz
  • o: * Cerca: un modello che sembra così "aa/bbbb/cccc" dove "/" è un separatore, "aa" è di due cifre, "bbbb" è una parola di qualsiasi la lunghezza e "cccc" sono quattro cifre tra 1900 e 2020 *

Forse potremmo creare un "traduttore posteriore" con un tipo di linguaggio SQL per creare espressioni regolari, invece di crearlo in modo geek.

Ecco alcuni esempi che sono fattibile:

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, "-"); 

Un'interfaccia grafica in cui si contrassegna il campione di testo o inserire, aggiungendo alla regex sarebbe possibile anche. Prima si contrassegna una data (il "campione"), e si sceglie se questo testo è già formattato, o se si sta costruendo un formato, anche quale tipo di formato è: testo libero, testo formattato, data, GUID o Scegli .. da formati esistenti (che è possibile memorizzare in una libreria).

Consente di progettare una specifica per questo e renderla open source ... Chiunque desidera partecipare?

+0

dalle risposte qui sotto sembra non solo che questo sia stato studiato ma effettivamente implementato !! – pashute

1

Loreto praticamente questo. È un'implementazione open source che utilizza le sottostringhe più lunghe comuni per generare le espressioni regolari. Ha bisogno di più esempi, naturalmente, però.

0

Oltre ad alimentare l'algoritmo di apprendimento con esempi di input "buono", è possibile alimentare input "cattivo" in modo da sapere cosa non cercare. Nessuna lettera in un numero di telefono, per esempio.

Problemi correlati