Domanda

Ho appena visto un'enorme espressione regolare per Java che mi ha fatto riflettere un po' sulla manutenibilità delle espressioni regolari in generale.Credo che la maggior parte delle persone, ad eccezione di alcuni spacciatori di perl, concorderebbe sul fatto che le espressioni regolari sono difficilmente mantenibili.

Stavo pensando a come risolvere questa situazione.Finora, l'idea più promettente che ho è usare a interfaccia fluente.Per fare un esempio, invece di:

Pattern pattern = Pattern.compile("a*|b{2,5}");

si potrebbe scrivere qualcosa del genere

import static util.PatternBuilder.*

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();

Pattern alternative = 
  or(
    string("a").anyTimes(),
    string("b").times(2,5)
  )
  .compile();

In questo brevissimo esempio, il modo comune di creare un'espressione regolare è ancora abbastanza leggibile da qualsiasi sviluppatore di talento mediocre.Tuttavia, pensa a quelle espressioni inquietanti che riempiono due o più righe di 80 caratteri ciascuna.Certo, l'interfaccia fluente (verbosa) richiederebbe diverse righe invece di solo due, ma sono sicuro che sarebbe molto più leggibile (quindi manutenibile).

Ora le mie domande:

  1. Conosci qualche approccio simile alle espressioni regolari?

  2. Sei d'accordo sul fatto che questo approccio potrebbe essere migliore rispetto all'utilizzo di semplici stringhe?

  3. Come progetteresti l'API?

  4. Utilizzeresti un'utilità così interessante nei tuoi progetti?

  5. Pensi che sarebbe divertente implementarlo?;)

MODIFICARE:Immagina che potrebbero esserci metodi che si trovano a un livello superiore rispetto ai semplici costrutti che tutti noi non usiamo da regex, ad es.

// matches aaaab@example.com - think of it as reusable expressions
Pattern p = string{"a").anyTimes().string("b@").domain().compile();

EDIT - breve riepilogo dei commenti:

È interessante leggere che la maggior parte delle persone pensa che le espressioni regolari siano qui per restare, anche se ci vogliono strumenti per leggerle e ragazzi intelligenti che pensino a come renderle gestibili.Anche se non sono sicuro che un'interfaccia fluida sia la soluzione migliore, sono sicuro che alcuni ingegneri intelligenti - noi?;) - dovremmo dedicare un po' di tempo a rendere le espressioni regolari una cosa del passato - è sufficiente che siano con noi da 50 anni, non credi?

TAGLIA APERTA

Il premio verrà assegnato all'idea migliore (non è richiesto alcun codice) per un nuovo approccio alle espressioni regolari.

EDIT - UN BEL ESEMPIO:

ecco il tipo di schema di cui sto parlando - complimenti extra al primo che riesce a tradurlo - RegexBuddies consentito (proviene da un progetto Apache tra l'altro) complimenti extra assegnati a chii E mez:è un modello di convalida dell'indirizzo e-mail conforme a RFC, sebbene sia RFC822 (Vedere ex-parrot.com), non 5322 - non sono sicuro però che ci sia una differenza - se sì, assegnerò i prossimi complimenti extra per una patch adatta al 5322 ;)

private static final String pattern = "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:"
    + "\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:("
    + "?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ "
    + "\\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\0"
    + "31]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\"
    + "](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+"
    + "(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:"
    + "(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)"
    + "?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\"
    + "r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?["
    + " \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)"
    + "?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t]"
    + ")*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?["
    + " \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*"
    + ")(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)"
    + "*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+"
    + "|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r"
    + "\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:"
    + "\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t"
    + "]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031"
    + "]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\]("
    + "?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?"
    + ":(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?"
    + ":\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?"
    + ":(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?"
    + "[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|"
    + "\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>"
    + "@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\""
    + "(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?"
    + ":[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\["
    + "\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-"
    + "\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|("
    + "?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;"
    + ":\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[(["
    + "^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\""
    + ".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\"
    + "]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\"
    + "[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\"
    + "r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]"
    + "|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\0"
    + "00-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\"
    + ".|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,"
    + ";:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?"
    + ":[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:["
    + "^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]"
    + "]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*("
    + "?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:("
    + "?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=["
    + "\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t"
    + "])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t"
    + "])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?"
    + ":\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|"
    + "\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:"
    + "[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\"
    + "]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)"
    + "?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\""
    + "()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)"
    + "?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>"
    + "@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?["
    + " \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,"
    + ";:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:"
    + "\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\["
    + "\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])"
    + "*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])"
    + "+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\"
    + ".(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:("
    + "?:\\r\\n)?[ \\t])*))*)?;\\s*)";
È stato utile?

Soluzione

Come si progetta l'API?

Vorrei prendere in prestito una pagina dal criteri di Hibernate API. Invece di utilizzare:

string("a").anyTimes().or().string("b").times(2,5).compile()

Utilizzare un modello come:

Pattern.or(Pattern.anyTimes("a"), Pattern.times("b", 2, 5)).compile()

Questa notazione è un po 'più conciso, e sento che è più facile da capire la gerarchia / struttura del modello. Ogni metodo potrebbe accettare una stringa o un frammento modello, come primo argomento.

Sei a conoscenza di qualsiasi approccio simile alle espressioni regolari?

Non estemporaneo, no.

Sei d'accordo che questo approccio potrebbe essere migliore di utilizzare stringhe semplici?

Sì, absolutetely ... se si utilizza regex per qualcosa di anche lontanamente complicato. Per i casi molto brevi e semplici, una stringa è più conveniente.

Vuoi utilizzare un programma di utilità come ad accurato nei vostri progetti?

Forse, come divenne provato / stabile ... a rotazione in un progetto di utilità più grande come Apache Commons potrebbe essere un punto a favore.

Pensi che questo sarebbe stato divertente attuazione? ;)

1

Altri suggerimenti

Martin Fowler suggerisce un'altra strategia.Vale a dire prendere parti significative della regex e sostituirle con variabili.Usa il seguente esempio:

 "^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*)" 

diventa

   String scoreKeyword = "^score\s+";
   String numberOfPoints = "(\d+)";
   String forKeyword = "\s+for\s+";
   String numberOfNights = "(\d+)";
   String nightsAtKeyword = "\s+nights?\s+at\s+";
   String hotelName = "(.*)";

   String pattern = scoreKeyword + numberOfPoints +
      forKeyword + numberOfNights + nightsAtKeyword + hotelName;

Che è molto più leggibile e manutenibile.

L'obiettivo dell'esempio precedente era quello di analizzare numberOfPoints, numberOfNights e hotelName da un elenco di stringhe come:

score 400 for 2 nights at Minas Tirith Airport

Potrebbe essere un po 'più facile per qualcuno senza alcuna esperienza regex, ma dopo che qualcuno impara il sistema, ancora non sarà in grado di leggere una regex normale altrove.

Inoltre, penso che la versione è più difficile da leggere per un esperto di regex.

mi sento di raccomandare l'annotazione la regex in questo modo:

Pattern pattern = Pattern.compile(
  "a*     # Find 0 or more a        \n" +
  "|      # ... or ...              \n" +
  "b{2,5} # Find between 2 and 5 b  \n",
Pattern.COMMENTS);

Questo è di facile lettura per qualsiasi livello di esperienza, e per gli inesperti, si insegna regex allo stesso tempo. Inoltre, i commenti possono essere adattati alla situazione per spiegare le regole di business dietro l'espressione regolare non solo la struttura.

Inoltre, uno strumento come RegexBuddy può prendere la vostra regex e tradurlo in:

Match either the regular expression below (attempting the next alternative only if this one fails) «a*»
   Match the character "a" literally «a*»
      Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Or match regular expression number 2 below (the entire match attempt fails if this one fails to match) «b{2,5}»
   Match the character "b" literally «b{2,5}»
      Between 2 and 5 times, as many times as possible, giving back as needed (greedy) «{2,5}»

Questo è un concetto intrigante, ma come viene presentato ci sono alcuni difetti.

Ma prima le risposte alle domande chiave poste:

Ora le mie domande:

1.Conosci qualche approccio simile alle espressioni regolari?

Nessuno che non sia già stato menzionato.E quelli che ho scoperto leggendo le domande e le risposte.

2.Sei d'accordo sul fatto che questo approccio potrebbe essere migliore rispetto all'utilizzo di semplici stringhe?

Se funziona come pubblicizzato, renderebbe sicuramente molto più semplice il debug delle cose.

3.Come progetteresti l'API?

Vedi i miei appunti nella sezione successiva.Prendo i tuoi esempi e la libreria .NET collegata come punto di partenza.

4.Utilizzeresti un'utilità così interessante nei tuoi progetti?

Indeciso.Non ho problemi a lavorare con la versione attuale delle espressioni criptiche regolari.E avrei bisogno di uno strumento per convertire le espressioni regolari esistenti nella versione in linguaggio fluente.

5.Pensi che sarebbe divertente implementarlo?;)

Mi piacerebbe elaborare il modo di livello superiore, piuttosto che scrivere il codice vero e proprio.Il che spiega il muro di testo che è questa risposta.


Ecco un paio di problemi che ho notato e il modo in cui li affronterei.

Struttura poco chiara.

Il tuo esempio sembra creare una regex concatenandola su stringhe.Questo non è molto robusto.Credo che questi metodi dovrebbero essere aggiunti agli oggetti String e Patern/Regex, perché renderanno l'implementazione e il codice più puliti.Inoltre è simile al modo classico in cui vengono definite le espressioni regolari.

Solo perché non riesco a vederlo funzionare in nessun altro modo, il resto delle mie annotazioni allo schema proposto presupporranno che tutti i metodi agiscano e restituiscano oggetti Pattern.

Modificare: Mi sembra di aver utilizzato le seguenti convenzioni ovunque.Quindi li ho chiariti e li ho spostati qui.

  • Metodi di istanza:aumento del modello.per esempio:catturare, ripetere, guardare intorno alle asserzioni.

  • Operatori:ordine delle operazioni.alternanza, concatenazione

  • Costanti:classi di caratteri, confini (al posto di \w, $, \b, ecc.)

Come verrà gestita l'acquisizione/raggruppamento?

L'acquisizione è una parte importante delle espressioni regolari.

Vedo che ogni oggetto Pattern viene archiviato internamente come cluster.(?:pattern) in termini Perl.Consentire ai token del modello di essere facilmente mescolati e mescolati senza interferire con altri pezzi.

Mi aspetto che l'acquisizione venga eseguita come metodo di istanza su un Pattern.Prendendo una variabile in cui memorizzare le stringhe corrispondenti.

pattern.capture(variable) memorizzerebbe il modello in variabile.Nel caso in cui l'acquisizione faccia parte di un'espressione da abbinare più volte, la variabile deve contenere un array di stringhe di tutte le corrispondenze per pattern.

Le lingue fluenti possono essere molto ambigue.

I linguaggi fluenti non sono adatti alla natura ricorsiva delle espressioni regolari.Occorre quindi considerare l’ordine delle operazioni.Il semplice concatenamento di metodi non consente espressioni regolari molto complesse.Esattamente la situazione in cui uno strumento del genere sarebbe utile.

Fa

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();

produrre /a*|b{2,5}/ O /(a*|b){2,5}/ ?

In che modo uno schema del genere gestirebbe l'alternanza annidata?Per esempio: /a*|b(c|d)|e/

Vedo tre modi per gestire l'alternanza nelle espressioni regolari

  1. Come operatore: pattern1 or pattern2 => pattern # /pattern1|pattern2/
  2. Come metodo di classe: Pattern.or( pattern1, pattern2[, pattern3]*) => pattern # /pattern1|patern2|patern3|...|/
  3. Come metodo di istanza: pattern1.or(pattern2) => pattern # /pattern1|patern2/

Gestirei la concatenazione allo stesso modo.

  1. Come operatore: pattern1 + pattern2 => pattern # /pattern1pattern2/
  2. Come metodo di classe: Pattern.concatenate( pattern1, pattern2[, pattern3]*) => pattern # /pattern1patern2patern3.../
  3. Come metodo di istanza: pattern1.then(pattern2) => pattern # /pattern1patern2/

Come estendere i modelli di uso comune

Lo schema proposto utilizzato .domain() che sembra essere una regex comune.Trattare i modelli definiti dall'utente come metodi non semplifica l'aggiunta di nuovi modelli.In un linguaggio come Java gli utenti della libreria dovrebbero sovrascrivere la classe per aggiungere metodi per i modelli comunemente usati.

Questo viene affrontato dal mio suggerimento di trattare ogni pezzo come un oggetto.È possibile creare un oggetto modello per ciascuna regex comunemente utilizzata, ad esempio la corrispondenza di un dominio.Considerando i miei precedenti pensieri sull'acquisizione, non sarebbe difficile garantire che l'acquisizione funzioni per più copie dello stesso modello comune che contiene una sezione catturata.

Dovrebbero esserci anche costanti per i modelli che corrispondono a varie classi di caratteri.

Ampiezza zero guarda le asserzioni

Espandendo il mio pensiero secondo cui tutti i pezzi dovrebbero essere implicitamente raggruppati.Guardarsi intorno nelle asserzioni non dovrebbe essere troppo difficile anche farlo con un metodo di istanza.

pattern.zeroWidthLookBehind() produrrebbe (?<patten).


Cose che devono ancora essere considerate.

  • Riferimenti posteriori:Si spera che non sia troppo difficile con l'acquisizione con nome discussa in precedenza
  • Come implementarlo concretamente.Non ho pensato troppo alla parte interna.È lì che avverrà la vera magia.
  • Traduzione:Dovrebbe davvero esserci uno strumento per tradurre da e verso le espressioni regolari classiche (diciamo il dialetto Perl) e il nuovo schema.La traduzione dal nuovo schema potrebbe far parte del pacchetto

Mettendo tutto insieme, la mia versione proposta di un modello che corrisponde a un indirizzo email:

Pattern domain_label = LETTER_CHARACTER + (LETTER_CHARACTER or "-" or DIGIT_CHARACTER).anyTimes()
Pattern domain = domain_label + ("." + domain_label).anyTimes()
Pattern pattern = (LETTER_CHARACTER + ALPHANUMERIC_CHARACTER + "@" + domain).compile

Col senno di poi, il mio schema si ispira in larga misura all'approccio in uso di Martin Fowler.Anche se non avevo intenzione che le cose andassero in questo modo, ciò rende sicuramente più gestibile l'utilizzo di un sistema del genere.Risolve anche uno o due problemi con l'approccio di Fowler (catturare l'ordine).

La mia umile tentativo può essere trovato su GitHub . Anche se non credo che valga la pena utilizzare per semplici espressioni, fornisce un paio di vantaggi a parte il miglioramento leggibilità:

  • Si prende cura di corrispondenza staffa
  • Gestisce la fuga di tutti i personaggi 'speciali' che possono portare rapidamente al diavolo backslash

Alcuni semplici esempi:

 // Matches a single digit
    RegExBuilder.build(anyDigit()); // "[0-9]"

 // Matches exactly 2 digits
    RegExBuilder.build(exactly(2).of(anyDigit())); // "[0-9]{2}"

 // Matches between 2 and 4 letters
    RegExBuilder.build(between(2,4).of(anyLetter())); // "[a-zA-Z]{2,4}"

E uno più complicata (che più o meno convalida gli indirizzi e-mail):

final Token ALPHA_NUM = anyOneOf(range('A','Z'), range('a','z'), range('0','9'));
final Token ALPHA_NUM_HYPEN_UNDERSCORE = anyOneOf(characters('_','-'), range('A','Z'), range('a','z'), range('0','9'));

String regexText = RegExBuilder.build(
 // Before the '@' symbol we can have letters, numbers, underscores and hyphens anywhere
    oneOrMore().of(
        ALPHA_NUM_HYPEN_UNDERSCORE
    ),
    zeroOrMore().of(
        text("."), // Periods are also allowed in the name, but not as the initial character
        oneOrMore().of(
            ALPHA_NUM_HYPEN_UNDERSCORE
        )
    ),
    text("@"),
 // Everything else is the domain name - only letters, numbers and periods here
    oneOrMore().of( 
        ALPHA_NUM
    ),
    zeroOrMore().of(
        text("."), // Periods must not be the first character in the domain
        oneOrMore().of(
            ALPHA_NUM
        )
    ),
    text("."), // At least one period is required
    atLeast(2).of( // Period must be followed by at least 2 letters (this is the TLD)
        anyLetter()
    )
);

Risposta breve: ho visto si è avvicinato da un rilascio di fibre e l'angolo di compilazione, che credo sia una cosa da considerare per questo

.

Risposta lunga: L'azienda per cui lavoro rende i motori di espressioni regolari basati su hardware per applicazioni di filtraggio dei contenuti aziendali. Pensare l'esecuzione di applicazioni anti-virus o firewall a velocità 20 GB / sec proprio nei router di rete piuttosto che prendere i cicli di server o processore di valore. La maggior parte delle applicazioni anti-virus, anti-spam o firewall sono un sacco di espressioni regex al centro.

In ogni caso, il modo in cui la regex di sono scritti ha un enorme impatto sulle prestazioni della scansione. È possibile scrivere regexs in molti modi diversi di fare la stessa cosa, e alcuni avranno prestazioni drasticamente più veloce. Abbiamo compilatori e linters scritto per i nostri clienti per aiutarli a mantenere e ottimizzare le loro espressioni.

Torna alla domanda del PO, invece di definire una nuova sintassi, vorrei scrivere un Linter (mi dispiace, il nostro è proprietaria) taglia e incolla regex in quella si rompe l'eredità di espressione regolare e l'uscita "correntemente l'inglese" per qualcuno per capire meglio. Vorrei anche aggiungere controlli delle prestazioni relative e suggerimenti per le modifiche comuni.

La risposta breve, per me, è che, una volta che si arriva a espressioni regolari (o altri pattern matching che fa la stessa cosa) che sono abbastanza a lungo da causare un problema ... si dovrebbe probabilmente essere considerato se sono lo strumento giusto per il lavoro, in primo luogo.

Onestamente, qualsiasi interfaccia fluida sembra che sarebbe più difficile da leggere rispetto a un'espressione regolare standard. Per davvero brevi espressioni, la versione fluente è prolisso, ma non troppo a lungo; è leggibile. Ma lo è anche l'espressione regolare per qualcosa che a lungo.

Per un'espressione regolare di medie dimensioni, un'interfaccia fluida diventa pesante; abbastanza a lungo che è difficile, se non impossibile, da leggere.

Per un lungo un'espressione regolare (cioè, l'indirizzo di posta elettronica uno), in cui l'espressione regolare è in realtà difficile (se non impossibile) per leggere, la versione fluente è diventato impossibile da leggere 10 pagine fa.

Sei a conoscenza di qualsiasi approccio simile alle espressioni regolari?

No, tranne che per la risposta precedente

Sei d'accordo che questo approccio potrebbe essere migliore di utilizzare stringhe semplici?

Un po '- penso invece di singoli caratteri per rappresentare costrutti, potremmo usare marcatura più descrittivo, ma dubito che sarebbe logica complessa più chiaro.

Come si progetta l'API?

convertito ogni costruire in nome di un metodo, e di gestire la funzione annidata chiama in modo che sia molto facile da prendere una stringa e metodo sostitutivo nomi in esso.

Credo che la maggior parte del valore sarà nel definire una libreria robusta di funzioni di utilità, come la corrispondenza "email", "numeri di telefono", "linee che non contengono X", ecc, che possono essere personalizzati.

Vuoi utilizzare un programma di utilità come ad accurato nei vostri progetti?

Forse -. Ma probabilmente solo per quelle più lunghe, in cui sarebbe più facile per le chiamate alle funzioni di debug di debug modifica della stringa, o dove c'è una bella funzione di utilità pronto per l'uso

Pensi che questo sarebbe stato divertente attuazione? ;)

Naturalmente!

In risposta all'ultima parte della domanda (per Kudos)

private static final String pattern = "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:"
    + "\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:("
    + "?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ "
    + "\\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\0"
    + "31]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\"
    + "](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+"
    + "(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:"
    + "(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)"
    + "?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\"
    + "r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?["
    + " \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)"
    + "?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t]"
    + ")*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?["
    + " \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*"
    + ")(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)"
    + "*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+"
    + "|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r"
    + "\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:"
    + "\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t"
    + "]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031"
    + "]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\]("
    + "?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?"
    + ":(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?"
    + ":\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?"
    + ":(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?"
    + "[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|"
    + "\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>"
    + "@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\""
    + "(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?"
    + ":[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\["
    + "\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-"
    + "\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|("
    + "?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;"
    + ":\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[(["
    + "^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\""
    + ".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\"
    + "]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\"
    + "[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\"
    + "r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]"
    + "|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\0"
    + "00-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\"
    + ".|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,"
    + ";:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?"
    + ":[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:["
    + "^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]"
    + "]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*("
    + "?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:("
    + "?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=["
    + "\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t"
    + "])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t"
    + "])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?"
    + ":\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|"
    + "\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:"
    + "[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\"
    + "]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)"
    + "?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\""
    + "()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)"
    + "?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>"
    + "@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?["
    + " \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,"
    + ";:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:"
    + "\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\["
    + "\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])"
    + "*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])"
    + "+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\"
    + ".(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:("
    + "?:\\r\\n)?[ \\t])*))*)?;\\s*)";

corrisponde RFC indirizzi di posta elettronica compatibili: D

Un'espressione regolare è una descrizione di una macchina a stati finiti. La rappresentazione testuale classico non è necessariamente un male. È compatto, è relativamente unambigous ed è abbastanza ben adottato.

E 'possibile che una rappresentazione migliore sarebbe un diagramma di transizione di stato, ma che probabilmente sarebbe difficile da usare nel codice sorgente.

Una possibilità potrebbe essere quella di costruirlo da una varietà di contenitori e combinatore oggetti.

Qualcosa lungo la linea delle seguenti (trasformare questo da pseudo-codice di lingua scelta è lasciata come esercizio per l'ansioso):

domainlabel = oneormore(characterclass("a-zA-Z0-9-"))
separator = literal(".")
domain = sequence(oneormore(sequence(domainlabel, separator)), domainlabel)
localpart = oneormore(characterclassnot("@"))
emailaddress = sequence(localpart, literal("@"), domain)

Si noti che quanto sopra sarà in modo non corretto classificare arbritarily molti indirizzi e-mail quale documento valido che non sono conformi alla grammatica che stanno tenuti a seguire, come che la grammatica richiede più di un semplice FSM per la piena analisi. Non credo che sarebbe classificare erroneamente un indirizzo valido come non valido, però.

Si deve corrispondere al [^ @] + @ ([a-zA-Z0-9 -] +.) + ([A-zA-Z0-9 -] +).

4. Vuoi utilizzare un programma di utilità come ad accurato nei vostri progetti?

lo farei molto probabilmente non. Credo che questo sia un caso di utilizzare lo strumento giusto per il lavoro. Ci sono alcuni grandi risposte, come per esempio: 1.579.202 da Jeremy Stein. Recentemente ho "preso" le espressioni regolari su un recente progetto e trovato loro di essere molto utili così come sono, e se correttamente commentato che sono comprensibili se si conosce la sintassi.

Credo che il "conoscere la sintassi" parte è ciò che trasforma la gente fuori di espressioni regolari, a coloro che non capiscono loro aspetto arcano e criptico, ma sono uno strumento potente e in Informatica applicata (ad esempio, il software per la scrittura una vita) mi sento come professionisti intelligenti dovrebbe e deve essere in grado di imparare ad usarli e noi in modo appropriato.

Come si suol dire "Da un grande potere derivano grandi responsabilità". Ho visto la gente usa le espressioni regolari in tutto il mondo per tutto, ma usata con giudizio da qualcuno che ha preso il tempo di imparare a fondo la sintassi, sono incredibilmente utile; per me, l'aggiunta di un altro strato sarebbe in un certo senso sconfiggere il loro scopo, o almeno portare via il loro potere.

Questa solo la mia opinione e posso capire dove le persone stanno venendo da chi desidererebbe un quadro come questo, o che eviterebbero le espressioni regolari, ma non ho il tempo difficile sentire "espressioni regolari sono cattivi" da coloro che non hanno prendere il tempo per imparare a giocare e prendere una decisione informata.

Per rendere tutti felici (maestri regex e sostenitori di interfaccia dei fluidi), assicurarsi che l'interfaccia fluido in grado di emettere un appropriato schema di espressione regolare cruda, e anche prendere una regex regolari utilizzando un metodo di fabbrica e generare codice fluido per esso.

Quello che state cercando si può trovare qui: . Si tratta di un'espressione regolare buillder che segue il modello Design Wizard

Recentemente ho avuto questa stessa idea .

Il pensiero di attuare io stesso, ma poi ho trovato VerbalExpressions .

Mettiamo a confronto: Ho lavorato spesso con (N) query Hibernate ICriteria, che possono essere considerati un Fluent mappatura a SQL. Ero (e sono ancora) entusiasta di loro, ma ho fanno la query SQL più leggibile? No, più al contrario, ma un altro vantaggio è aumentato:. È diventato molto più facile costruire programmazione dichiarazioni, per creare una sottoclasse di loro e creare le proprie astrazioni etc

Quello che voglio dire è che l'utilizzo di una nuova interfaccia per una data lingua, se fatto bene, può rivelarsi utile, ma non pensare troppo alta di esso. In molti casi non sarà più facile da leggere (classi di personaggi nidificato sottrazione, coglie in look-dietro, se-ramificazione per citarne alcuni concetti avanzati che sarà difficile per combinare correntemente). Ma in altrettanti casi, i benefici di una maggiore flessibilità superano l'overhead aggiunto di sintassi complessità.

Per aggiungere alla vostra lista di possibili approcci alternativi e di prendere questo fuori del contesto di sole Java, prendere in considerazione la sintassi LINQ. Ecco quello che potrebbe sembrare (un po 'artificiosa) (from, where e select sono le parole chiave in LINQ):

// for ^str(aa|bb){3}
from part in mystring
where part startswith "str"
and part hasgroups "aa" or "bb" as first    /* "aa" or "bb" in group 'first' */
and part repeats first 3                    /* repeat group 'first' 3 times */
select part + "extra"                       /* can contain complete statement block */

solo una vaga idea, lo so. La cosa buona di LINQ è che viene controllato dal compilatore, una sorta-di lingua in una lingua. Per impostazione predefinita, LINQ può anche essere espresso come la sintassi incatenato fluente, il che lo rende, se ben progettato, compatibile con altri linguaggi OO.

dico andare per esso, sono sicuro che sia divertente da implementare.

Io suggerisco di usare un modello di query (simile a jQuery, Django ORM), in cui ogni funzione restituisce un oggetto query, in modo da poterli concatenare insieme.

any("a").some("b").one("@").some(chars).one(".").some(chars) //a*b+@\w+\.\w+

dove chars è predefinito per adattarsi a qualsiasi carattere.

or può essere ottenuto utilizzando le scelte:

any("a").choice("x", "z") // a(x|z)

L'argomento di ogni funzione può essere una stringa o un'altra query. Ad esempio, la variabile chars cui sopra può essere definito come una query:

//this one is ascii only
chars = raw("a-zA-Z0-9")

E così, si può avere una funzione di "grezzo" che accetta una stringa regex come input se ci si sente a ingombrante per usare il sistema di interrogazione fluente.

In realtà, queste funzioni possono solo tornare regex cruda, e concatenamento loro è semplicemente concatenando queste stringhe prime espressioni regolari.

any("a") ---> "a*"
raw("b+") ----> "b+"
one(".") ---> "\."
choice("a", "b") ----> (a|b)

Non sono sicuro che la sostituzione regexp con un'API fluente avrebbe portato molto.

Si noti che io non sono un mago regexp (devo rileggere il documento quasi ogni volta che ho bisogno di creare un regexp).

Un'API fluente avrebbe alcun regexp media complessità (diciamo ~ 50 caratteri) ancora più complesso di quanto richiesto e non più facile da leggere, alla fine, anche se può migliorare la creazione di una regexp in un IDE, grazie al completamento del codice. Ma il codice di manutenzione rappresenta in genere un costo superiore a quello sviluppo di codice.

In realtà, io non sono nemmeno sicuro che sarebbe stato possibile avere un'API abbastanza intelligente per fornire davvero sufficiente una guida per lo sviluppatore quando si crea una nuova espressione regolare, non parliamo di casi ambigui, come indicato nella risposta precedente.

Lei ha citato un esempio di espressione regolare per un RFC. Sono sicuro che il 99% (c'è ancora 1% speranza ;-)) che ogni API non avrebbe fatto che ad esempio affatto più semplice, ma al contrario che sarebbe solo rendere più complessa la lettura! Questo è un tipico esempio in cui non si desidera utilizzare regexp comunque!

Anche per quanto riguarda la creazione di espressioni regolari, a causa del problema dei modelli ambigui, è probabile che con un'API fluente, si sarebbe mai venuto con l'espressione giusta la prima volta, ma avrebbe dovuto cambiare più volte fino ad ottenere ciò che veramente desiderare.

Non commettere errori, io amo le interfacce fluente; Ho sviluppato alcune librerie che li utilizzano, e utilizzare diverse librerie terze parti basati su di essi (ad esempio FEST per Java di test). Ma non credo che possano essere il martello d'oro per qualsiasi problema.

Se si considera esclusivamente Java, penso che il problema principale con espressioni regolari è la necessario fuga di backslash in Java costanti stringa. Questo è un punto che lo rende incredibilmente difficile da creare e comprendere regexp in Java. Quindi, il primo passo per migliorare la Java regexp sarebbe, per me, essere un cambiamento di lingua, alla Groovy , dove le costanti stringa non hanno bisogno di fuggire backslash.

finora che sarebbe la mia unica proposta per migliorare regexp in Java.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top