Question

Je viens de voir un énorme regex pour Java qui m'a fait penser un peu maintenabilité des expressions régulières en général. Je crois que la plupart des gens - à l'exception de quelques fauteurs de badass perl - seraient d'accord que les expressions régulières ne sont guère maintenable

.

Je pensais à la façon dont cette situation pourrait être fixée. Jusqu'à présent, l'idée la plus prometteuse j'utilise un couramment. Pour donner un exemple, au lieu de:

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

on pourrait écrire quelque chose comme ceci

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

Dans cet exemple très court, la manière commune de créer une expression régulière est encore très lisible à tout développeur de talent médiocre. Cependant, pensez à ces expressions fantasmagoriques qui remplissent deux ou plusieurs lignes avec 80 caractères chacun. Bien sûr, le (bavard) interface fluide nécessiterait plusieurs lignes au lieu de deux, mais je suis sûr que ce serait beaucoup plus facile à lire (donc maintenable).

Maintenant, mes questions:

  1. Connaissez-vous une approche similaire à des expressions régulières?

  2. Estimez-vous que cette approche pourrait être mieux que d'utiliser des chaînes simples?

  3. Comment voulez-vous concevoir l'API?

  4. Souhaitez-vous utiliser un utilitaire pur dans vos projets?

  5. Pensez-vous que ce serait amusant la mise en œuvre? ;)

EDIT: Imaginez qu'il pourrait y avoir des méthodes qui sont à un niveau plus élevé que des constructions simples que nous avons tous pas de regex, par exemple

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

EDIT - bref résumé des commentaires:

Il est intéressant de lire que la plupart des gens pensent que les expressions régulières sont là pour rester - bien qu'il faut des outils pour les lire et les gars intelligents pour penser à des façons de les faire maintenable. Bien que je ne suis pas sûr qu'une interface fluide est la meilleure façon d'y aller, je suis sûr que certains ingénieurs intelligents - nous? ;) - devrait passer un peu de temps pour faire des expressions régulières une chose du passé - il suffit qu'ils ont été avec nous depuis 50 ans savent, ne pensez-vous pas

Ouvrir BOUNTY

La prime sera attribué à la meilleure idée (pas de code nécessaire) pour une nouvelle approche des expressions régulières.

EDIT - un bon exemple:

voici le genre de modèle que je parle - kudos supplémentaires au premier qui est capable de traduire - RegexBuddies permis (il est d'un projet Apache BTW) kudos supplémentaires attribué à et href="https://stackoverflow.com/users/20010/mez"> mez : il est un modèle de validation d'adresse e-mail compatible RFC - bien que son RFC822 (voir < a href = "http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html" rel = "nofollow noreferrer"> ex-parrot.com ), pas 5322 - ne sais pas s'il y a une différence bien - si oui, je vais prochain prix de kudos supplémentaires pour un patch pour adapter 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*)";
Était-ce utile?

La solution

Comment voulez-vous concevoir l'API?

J'emprunter une page de l'API de critères Hibernate. Au lieu d'utiliser:

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

utiliser un modèle comme:

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

Cette notation est un peu plus concis, et je me sens qu'il est plus facile de comprendre la hiérarchie / structure du modèle. Chaque méthode peut accepter soit une chaîne, ou un fragment de motif, le premier argument.

Savez-vous de toute approche similaire à des expressions régulières?

Non désinvolture, non.

Estimez-vous que cette approche pourrait être mieux que d'utiliser des cordes simples?

Oui, absolutetely ... si vous utilisez regex pour quoi que ce soit à distance compliqué. Pour les cas très courts et simples, une chaîne est plus commode.

Souhaitez-vous utiliser un utilitaire pur dans vos projets?

Peut-être, comme il est devenu roulement prouvé / stable ... dans un projet utilitaire plus grand comme Apache Commons pourrait être un plus.

Pensez-vous que ce serait amusant la mise en œuvre? ;)

1

Autres conseils

Martin Fowler suggère une autre stratégie . A savoir prendre des parties significatives de l'expression rationnelle et de les remplacer par des variables. Il utilise par exemple suivant:

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

devient

   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;

Ce qui est beaucoup plus lisible et maintenable.

Le but de l'exemple précédent était d'analyser numberOfPoints, numberOfNights et hotelName sur une liste de chaînes comme:

score 400 for 2 nights at Minas Tirith Airport

Il est peut-être un peu plus facile pour quelqu'un sans aucune expérience regex, mais après que quelqu'un apprend votre système, il ne peut toujours pas être en mesure de lire une expression rationnelle normale ailleurs.

En outre, je pense que votre version est plus difficile à lire pour un expert regex.

Je recommande annoter la regex comme ceci:

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

Il est facile à lire pour tout niveau d'expérience, et pour les novices, il enseigne regex en même temps. En outre, les commentaires peuvent être adaptés à la situation pour expliquer les règles métier derrière l'expression régulière plutôt que la structure.

En outre, un outil comme RegexBuddy peut prendre votre regex et le traduire en:

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}»

Ce concept est intéressant, mais comme il est présenté il y a quelques défauts.

Mais premières réponses aux questions importantes posées:

Maintenant, mes questions:

1. Connaissez-vous une approche similaire à des expressions régulières?

Aucun de ceux qui ne l'ont pas déjà été mentionné. Et ceux que j'ai découvert en lisant la question et les réponses.

2. Estimez-vous que cette approche pourrait être mieux que d'utiliser des cordes simples?

Si cela fonctionne comme annoncé, il aurait certainement fait des choses beaucoup plus facile à déboguer.

3. Comment voulez-vous concevoir l'API?

Voir mes notes dans la section suivante. Je prends vos exemples et la bibliothèque .NET liés comme point de départ.

4. Souhaitez-vous utiliser un utilitaire pur dans vos projets?

Indécis. Je n'ai aucun problème à travailler avec la version actuelle de Cryptic expressions régulièrement. Et je besoin d'un outil pour convertir les expressions régulières existant à la version couramment.

5. Pensez-vous que ce serait amusant la mise en œuvre? ;)

J'aime travailler le plus haut niveau comment, que d'écrire le code réel. Ce qui explique le mur de texte qui est cette réponse.


Voici quelques problèmes que j'ai remarqué, et la façon dont je y faire face.

Structure Incertain.

Votre exemple semble créer une regex en enchaînant sur les chaînes. Ce n'est pas très robuste. Je crois que ces méthodes doivent être ajoutées aux objets String et Patern / Regex, car il fera la mise en œuvre et plus propre code. En outre, il est semblable à la façon dont les expressions régulières sont classiquement définies.

Juste parce que je ne peux pas le voir travailler d'une autre manière, le reste de mes annotations au régime proposé suppose que toutes les méthodes agissent et renvoyer les objets de motif.

Modifier Il me semble avoir utilisé dans toutes les conventions suivantes. Alors je les ai clarifiées et les déplacer ici.

  • Les méthodes d'instance: augmentation de motif. par exemple:. la capture, la répétition, regardez autour des affirmations

  • Opérateurs: ordre des opérations. alternance, concaténation

  • Constantes: classes de personnages, les limites (INPLACE de \ w, $, \ b, etc.)

Comment va capturer / cluster manipuler?

collectez est une grande partie des expressions régulières.

Je vois chaque objet de motif étant stocké en interne comme un cluster. (: Motif) en termes Perl. En tenant compte de modèle jetons pour être facilement mélangés et mêlés sans interférer avec d'autres pièces.

Je me attends capturant à faire comme une méthode d'instance sur un motif. Prendre une variable pour stocker la chaîne correspondante [s].

pattern.capture(variable) stockerait modèle dans la variable. Dans le cas où la capture fait partie d'une expression à être adapté plusieurs fois, la variable doit contenir un tableau de chaînes de tous les matches pour motif.

langues Fluent peut être très ambigu.

langues Fluent ne sont pas bien adaptés à la nature récurrente des expressions régulières. Donc attention doit être accordée à l'ordre des opérations. Juste enchaînant les méthodes ensemble ne permet pas d'expressions régulières très complexes. Exactement la situation où un tel outil serait utile.

Est

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

produits /a*|b{2,5}/ ou /(a*|b){2,5}/?

Comment un tel système gérer l'alternance imbriqué? Par exemple: /a*|b(c|d)|e/

Je vois trois façons de gérer l'alternance dans les expressions régulières

  1. En tant qu'opérateur: pattern1 or pattern2 => pattern # /pattern1|pattern2/
  2. En tant que méthode de classe: Pattern.or( pattern1, pattern2[, pattern3]*) => pattern # /pattern1|patern2|patern3|...|/
  3. En tant que méthode d'instance: pattern1.or(pattern2) => pattern # /pattern1|patern2/

Je concaténation gérer de la même manière.

  1. En tant qu'opérateur: pattern1 + pattern2 => pattern # /pattern1pattern2/
  2. En tant que méthode de classe: Pattern.concatenate( pattern1, pattern2[, pattern3]*) => pattern # /pattern1patern2patern3.../
  3. En tant que méthode d'instance: pattern1.then(pattern2) => pattern # /pattern1patern2/

Comment prolonger pour couramment utilisés patterns

Le schéma proposé utilisé .domain() qui semble être une expression rationnelle commune. Pour traiter les modèles définis par l'utilisateur en tant que méthodes ne permet pas d'ajouter facilement de nouveaux modèles. Dans une langue comme les utilisateurs Java de la bibliothèque aurait pour passer outre la classe pour ajouter des méthodes pour les modèles couramment utilisés.

Cette question est traitée par ma suggestion de traiter chaque pièce comme un objet. Un objet de modèle peut être créé pour chaque expression rationnelle utilisée comme correspondant à un nom de domaine par exemple. Compte tenu de mes réflexions antérieures sur la capture il ne serait pas trop difficile de faire en sorte que la capture fonctionne pour plusieurs copies du même modèle commun qui contient une section capturée.

Il devrait également être des constantes pour les modèles correspondant à différentes classes de caractères.

zéro regard largeur autour des affirmations

L'expansion de mes pensées que toutes les pièces doivent être implicitement regroupés. affirmations ne devraient pas être trop dur Regardez autour de vous aussi faire avec une méthode d'instance.

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


Les choses qui doivent encore être pris en considération.

  • Les références arrières: Espérons pas trop dur avec la capture discuté plus tôt appelé
  • Comment mettre en œuvre réellement. Je n'ai pas donné les entrailles trop pensé. Il est où la vraie magie va se passer.
  • Traduction: Il devrait vraiment être un outil traduisons de regexs classique (dire dialecte Perl) et le nouveau système. La traduction du nouveau régime pourrait être une partie du paquet

Mettre tous ensemble, ma version proposée d'un modèle qui correspond à une adresse e-mail:

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

Avec le recul, mon système emprunte beaucoup à l'approche de Martin Fowler en cours d'utilisation. Bien que je ne voulais pas que les choses vont de cette façon, il est certainement utiliser un tel système plus facilement. Il aborde également un problème ou deux à l'approche de Fowler (ordre de capture).

Mon humble tentative se trouve sur GitHub . Bien que je ne pense pas qu'il soit utile d'utiliser des expressions simples, il fournit quelques avantages en dehors de l'amélioration de la lisibilité:

  • Il prend soin de correspondance de support
  • Il gère des échappements de tous les caractères « spéciaux » qui peut rapidement conduire à l'enfer backslash

Quelques exemples simples:

 // 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}"

Et plus compliquée (qui plus ou moins valide les adresses 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()
    )
);

Il y a un couramment bibliothèque pour .NET expressions rationnelles.

Réponse courte: Je l'ai vu approché d'un effilochage et l'angle compilation, qui je pense est quelque chose à prendre en compte pour cette

.

Réponse longue: La société pour laquelle je travaille fabrique des moteurs d'expression régulière à base de matériel pour des applications de filtrage de contenu d'entreprise. Pensez d'exécuter des applications antivirus ou pare-feu à des vitesses de 20 Go / s dans les routeurs droite du réseau plutôt que de prendre des cycles précieux de serveur ou d'un processeur. La plupart des anti-virus, les applications anti-spam ou pare-feu sont un tas d'expressions regex au cœur.

De toute façon, la façon dont sont écrits sont les regex a un impact énorme sur les performances du balayage. Vous pouvez écrire regexs de plusieurs façons différentes de faire la même chose, et certains ont des performances considérablement plus rapide. Nous avons compilateurs écrit et bourres pour nos clients pour les aider à maintenir et régler leurs expressions.

Retour à la question de l'OP, plutôt que de définir une nouvelle syntaxe tout, je voudrais écrire un linter (désolé, la nôtre est propriétaire) couper et coller des regex dans cette casseront de bas héritage regex et de sortie « anglais courant » pour quelqu'un de comprendre mieux. Je voudrais aussi ajouter des contrôles de performance relatifs et suggestions de modifications communes.

La réponse, pour moi, est que, une fois que vous obtenez à des expressions régulières (ou autre correspondance de motif qui fait la même chose) qui sont assez longtemps pour causer un problème ... vous devriez probablement envisager si elles sont l'outil pour le travail en premier lieu.

Honnêtement, toute interface fluide semble que ce serait plus difficile à lire qu'une expression régulière standard. Pour les expressions très court, la version fluide est bavard, mais pas trop longtemps; il est lisible. Mais il en est l'expression régulière pour quelque chose qui longtemps.

Pour une expression régulière de taille moyenne, une interface fluide devient difficile à manier; assez longtemps qu'il est difficile, sinon impossible, à lire.

Pour une longue expression régulière (par exemple, l'adresse e-mail un), où l'expression régulière est en fait difficile (voire impossible) à lire, la version couramment est devenu impossible de lire il y a 10 pages.

Savez-vous de toute approche similaire à des expressions régulières?

Non, sauf pour la réponse précédente

Estimez-vous que cette approche pourrait être mieux que d'utiliser des cordes simples?

Trier de - je pense au lieu de caractères simples pour représenter des constructions, on pourrait utiliser un balisage plus descriptif, mais je doute qu'il serait logique complexe plus clair.

Comment voulez-vous concevoir l'API?

Traduisez chaque construction dans un nom de méthode, et permettre la fonction d'imbrications de sorte qu'il est très facile de prendre des noms de chaîne et de la méthode de substitution en elle.

Je pense que la majorité de la valeur dans la définition d'une bibliothèque robuste de fonctions utilitaires, comme correspondant à « e-mails », « numéros de téléphone », « lignes qui ne contiennent pas X », etc. qui peuvent être personnalisés.

Souhaitez-vous utiliser un utilitaire pur dans vos projets?

Peut-être. - mais probablement seulement pour les plus longs, où il serait plus facile d'appels de fonction de débogage que l'édition de chaîne de débogage, ou où il y a une belle fonction d'utilité prête à l'emploi

Pensez-vous que ce serait amusant la mise en œuvre? ;)

Bien sûr!

En réponse à la dernière partie de la question (pour 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*)";

correspond à des adresses électroniques compatibles RFC: D

Une expression régulière est une description d'une machine à états finis. La représentation textuelle classique est pas nécessairement mauvais. Il est compact, il est relativement non ambigu et il est assez bien adopté.

Il se peut qu'une meilleure représentation serait un diagramme de transition d'état, mais ce serait sans doute difficile à utiliser dans le code source.

Une possibilité serait de le construire à partir d'une variété de conteneurs et des objets combinateur.

Quelque chose le long de la ligne de ce qui suit (ce tournant de pseudo-code à la langue de choix est laissé comme un exercice pour la hâte):

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

Notez que ce qui précède classera mal arbritarily plusieurs adresses e-mail comme étant valide qui ne sont pas conformes à la grammaire, ils sont tenus de suivre, comme la grammaire nécessite plus qu'un simple EFM pour l'analyse complète. Je ne crois pas que ce serait une adresse valide une qualification erronée comme non valide, cependant.

Il doit correspondre à [^ @] + @ ([a-zA-Z0-9 -] +.) + ([A-zA-Z0-9 -] +).

4. Souhaitez-vous utiliser un utilitaire pur dans vos projets?

je serais très probablement pas. Je pense que cela est un cas d'utilisation de l'outil pour le travail. Il y a quelques réponses ici telles que: 1579202 de Jeremy Stein. J'ai récemment « obtenu » des expressions régulières sur un récent projet et nous les avons trouvés très utiles comme ils le sont, et quand bien commenté qu'ils sont compréhensibles si vous connaissez la syntaxe.

Je pense que la « connaissance de la syntaxe » est partie ce qui rebute les gens aux expressions régulières, à ceux qui ne comprennent pas qu'ils regardent Arcane et cryptique, mais ils sont un outil puissant et appliqué informatique (par exemple un logiciel d'écriture pour vie) Je me sens comme les professionnels intelligents devrait et doit être en mesure d'apprendre à les utiliser et nous les convenablement.

Comme on dit « Avec une grande puissance vient une grande responsabilité. » Je l'ai vu des gens utiliser des expressions régulières partout pour tout, mais utilisé judicieusement par quelqu'un qui a pris le temps d'apprendre la syntaxe à fond, ils sont incroyablement utiles; pour moi, en ajoutant une autre couche serait d'une manière vaincre leur but, ou au moins enlever leur pouvoir.

juste mon opinion et je peux comprendre où les gens viennent qui désirerait un cadre comme celui-ci, ou qui éviteraient des expressions régulières, mais je audience du mal « Les expressions régulières sont mauvais » de ceux qui n'ont pas prendre le temps de les apprendre et de prendre une décision éclairée.

Pour tout le monde heureux (maîtres regex et partisans de l'interface fluide), assurez-vous que l'interface fluide peut produire un motif regex cru approprié, et aussi prendre une regex régulière en utilisant une méthode de fabrication et de générer du code fluide pour elle.

Ce que vous cherchez se trouve ici: . Il est une expression régulière buillder qui suit le Assistant Design Pattern

J'ai récemment cette même idée .

Pensée de la mise en œuvre moi-même, mais je l'ai trouvé VerbalExpressions .

Comparons: Je travaille souvent avec (N) requêtes Hibernate ICriteria, qui peut être considéré comme une Courant mapping à SQL. J'étais (et suis toujours) enthousiastes à l'idée, mais ont-ils fait des requêtes SQL plus lisible? Non, plus au contraire, mais un autre avantage a augmenté:. Il est devenu beaucoup plus facile de construire des déclarations par programmation, pour les sous-classe et de créer vos propres abstractions etc

Ce que je veux dire est que l'utilisation d'une nouvelle interface pour une langue donnée, si bien fait, peut se révéler utile, mais ne pense pas que trop d'éloges. Dans de nombreux cas, il ne deviendra pas plus facile à lire (classes de caractères de soustraction imbriquées, captures dans regarder en arrière, si ramification pour ne nommer que quelques concepts avancés qui seront difficiles à combiner couramment). Mais dans tout autant de cas, les avantages d'une plus grande flexibilité l'emportent sur les frais généraux de complexité de la syntaxe.

Pour ajouter à votre liste d'approches alternatives possibles et de prendre ce hors du contexte de seulement Java, pensez à la syntaxe LINQ. Voici ce qu'il pourrait ressembler (un peu artificiel) (from, where et select sont des mots clés dans 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 */

juste une vague idée, je sais. La bonne chose est que LINQ, il est vérifié par le compilateur, une sorte-de la langue dans une langue. Par défaut, LINQ peut également être exprimée en syntaxe chaîné fluide, ce qui en fait, si elle est bien conçue, compatible avec d'autres langages OO.

Je dis aller, je suis sûr que c'est amusant de mettre en œuvre.

Je suggère d'utiliser un modèle de requête (similaire à jQuery, django ORM), où chaque fonction retourne un objet de requête, de sorte que vous pouvez les enchaîner ensemble.

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

chars est prédéfinie pour être compatibles avec tous les caractères.

or peut être obtenue en utilisant des choix:

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

L'argument à chaque fonction peut être une chaîne ou d'une autre requête. Par exemple, la variable chars mentionné ci-dessus peut être définie comme une requête:

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

Et donc, vous pouvez avoir une fonction « brute » qui accepte une chaîne regex en entrée si elle se sent à la lourdeur d'utiliser le système de requête couramment.

En fait, ces fonctions peuvent simplement retourner regex brute et les enchaînant est tout simplement concaténer ces chaînes de regex brut.

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

Je ne suis pas sûr que le remplacement regexp avec une API couramment apporterait beaucoup.

Notez que je ne suis pas un sorcier regexp (je dois relire la doc presque chaque fois que je dois créer une expression rationnelle).

Une API couramment ferait une expression rationnelle de complexité moyenne (disons ~ 50 caractères) encore plus complexe que nécessaire et non plus facile à lire à la fin, même si elle peut améliorer la création d'une expression rationnelle dans un IDE, grâce à l'achèvement du code. Mais la maintenance du code représente généralement un coût plus élevé que le développement de code.

En fait, je suis fournir même pas sûr qu'il serait possible d'avoir une API assez intelligent pour vraiment assez d'indications pour le développeur lors de la création d'une nouvelle expression rationnelle, ne parle pas des cas ambigus, comme mentionné dans une réponse précédente.

Vous avez mentionné un exemple pour une expression rationnelle RFC. Je suis sûr à 99% (il y a encore 1% espoir ;-)) que toute API ne ferait pas cet exemple plus simple, mais au contraire qui ne le rendre plus complexe à lire! C'est un exemple typique où vous ne voulez pas utiliser regexp quand même!

Même en ce qui concerne la création de regexp, en raison du problème des motifs ambigus, il est probable que, avec une API couramment, vous ne jamais l'expression à droite la première fois, mais il faut changer plusieurs fois jusqu'à ce que vous obtenez ce que vous avez vraiment voulez.

Ne vous méprenez pas, je ne l'aime interfaces couramment; J'ai développé quelques bibliothèques qui les utilisent, et j'utiliser plusieurs bibliothèques 3e partie basées sur les tests (par exemple FEST pour Java). Mais je ne pense pas qu'ils peuvent être le marteau d'or pour tout problème.

Si l'on considère Java exclusivement, je pense que le principal problème est le regexps avec Évasion nécessaire antislashs dans les constantes de chaîne Java. C'est un point qui le rend incroyablement difficile à créer et à comprendre regexp en Java. Par conséquent, la première étape pour améliorer Java regexp serait, pour moi, un changement de langue, a la Groovy , où les constantes de chaîne ne doivent pas échapper antislashs.

Jusqu'à présent, ce serait ma seule proposition visant à améliorer regexp en Java.

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