سؤال

لقد رأيت ضخمة regex جافا الذي جعلني أفكر قليلا عن الصيانة من التعبيرات العادية في العام.وأعتقد أن معظم الناس - ما عدا بعض بدس بيرل مروجي - يتفقون على أن التعبيرات العادية بالكاد للصيانة.

كنت أفكر كيف أن هذا الوضع يمكن أن تكون ثابتة.حتى الآن الواعدة فكرة لدي هو استخدام يجيد واجهة.على سبيل المثال, بدلا من:

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

يمكن للمرء أن يكتب شيئا من هذا القبيل

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

في هذا قصيرة جدا على سبيل المثال طريقة شائعة خلق العادية التعبير لا تزال قابلة للقراءة على أي المتوسط المطور الموهوبين.بيد أن التفكير في تلك عصبي التعبيرات التي تملأ اثنين أو أكثر من خطوط 80 حرفا لكل منهما.بالتأكيد, (مطول) بطلاقة واجهة يتطلب عدة أسطر بدلا من اثنين فقط ، ولكن أنا متأكد من أنه سيكون أكثر قابلية للقراءة (وبالتالي للصيانة).

الآن أسئلتي:

  1. هل تعرف من أي نهج مماثل إلى التعبيرات العادية?

  2. هل توافق على أن هذا النهج يمكن أن يكون أفضل من استخدام بسيطة السلاسل ؟

  3. كيف يمكنك تصميم API ؟

  4. يمكنك استخدام هذه الأداة أنيق في مشاريعك ؟

  5. هل تعتقد أن هذا سيكون ممتعا تنفيذ?;)

تحرير: تخيل أنه يمكن أن يكون هناك الأساليب التي هي على مستوى أعلى من مجرد بنيات نحن جميعا لا من regex مثلا

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

تحرير - ملخص قصير من التعليقات:

انها مثيرة للاهتمام أن تقرأ أن معظم الناس يعتقدون أن التعبيرات العادية هي البقاء هنا - على الرغم من أنه يأخذ أدوات قراءتها و الرجال الذكية إلى التفكير في طرق لجعلها للصيانة.بينما أنا لست متأكدا أن يجيد واجهة هو أفضل وسيلة للذهاب ، أنا متأكد من أن بعض المهندسين الذكية نحن ؟ ;) - يجب أن تنفق بعض الوقت لجعل التعبيرات العادية شيء من الماضي - يكفي أن كانوا معنا لمدة 50 عاما تعرف, ألا تعتقد ذلك ؟

فتح فضله

الجائزة ستمنح لأفضل فكرة (أي رمز المطلوبة) اتباع نهج جديد في التعبيرات العادية.

تحرير - لطيفة سبيل المثال:

هنا هو نوع من نمط أتحدث عنه - إضافية مجد أول واحد الذي هو قادرة على ترجمته - RegexBuddies يسمح (إنه من أباتشي المشروع راجع للشغل) إضافية مجد منح chii و mez:انها المتوافقة مع RFC عنوان البريد الإلكتروني التحقق من صحة نمط - على الرغم من أن RFC822 (انظر ex-parrot.com) لا 5322 - لست متأكدا إذا كان هناك فرق الرغم من ذلك - إذا كان الجواب نعم ، سوف جائزة إضافية المقبلة مجد التصحيح لتناسب 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*)";
هل كانت مفيدة؟

المحلول

كيف يمكنك تصميم واجهة برمجة التطبيقات؟

أود استعارة صفحة من API لمعايير السبات. بدلا من استخدام:

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

استخدم نمطًا مثل:

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

هذا الترميز أكثر إيجازًا قليلاً ، وأشعر أنه من الأسهل فهم التسلسل الهرمي/بنية النمط. يمكن أن تقبل كل طريقة إما سلسلة ، أو جزء نمط ، كوسيطة أول.

هل تعرف أي نهج مماثل للتعبيرات العادية؟

ليس غير مهذب ، لا.

هل توافق على أن هذا النهج يمكن أن يكون أفضل من استخدام سلاسل بسيطة؟

نعم ، بشكل مطلق ... إذا كنت تستخدم Regex لأي شيء معقد عن بعد. لحالات قصيرة وبسيطة للغاية ، تكون السلسلة أكثر ملاءمة.

هل يمكنك استخدام هذه الأداة المساعدة الأنيقة في مشاريعك؟

ربما ، كما أصبح مثبتًا/مستقرًا ... قد يكون تدحرجه إلى مشروع فائدة أكبر مثل Apache Commons زائد.

هل تعتقد أن هذا سيكون ممتعًا للتنفيذ؟ ؛)

+1

نصائح أخرى

مارتن فاولر يقترح استراتيجية أخرى. وهي أخذ أجزاء ذات مغزى من regex واستبدالها بالمتغيرات. يستخدم مثال التالي:

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

يصبح

   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;

وهو أكثر قابلية للقراءة والصيانة.

كان الهدف من المثال السابق هو تحليل عدد النقاط ، رقم NumberOfFnights واسم فندق من قائمة الأوتار مثل:

score 400 for 2 nights at Minas Tirith Airport

قد يكون الأمر أسهل قليلاً على شخص ما دون أي تجربة regex ، ولكن بعد أن يتعلم شخص ما نظامك ، لن يتمكن من قراءة regex العادية في مكان آخر.

أيضًا ، أعتقد أن نسختك يصعب قراءة خبير Regex.

أود أن أوصي بتعليق regex مثل هذا:

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

من السهل قراءتها لأي مستوى خبرة ، وللحصول على عديمي الخبرة ، فإنه يعلم Regex في نفس الوقت. أيضًا ، يمكن تصميم التعليقات مع الموقف لشرح قواعد العمل وراء Regex بدلاً من مجرد الهيكل.

أيضا ، أداة مثل regexbuddy يمكن أن تأخذ regex الخاص بك وترجمته إلى:

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

هذا مفهوم مثير للاهتمام ، ولكن كما هو مقدم هناك بعض العيوب.

لكن الإجابات الأولى على الأسئلة الرئيسية التي يتم طرحها:

الآن أسئلتي:

1. هل تعرف أي نهج مماثل للتعبيرات العادية؟

لا شيء لم يتم ذكره بالفعل. وأولئك الذين اكتشفتهم من خلال قراءة السؤال والأجوبة.

2. هل توافق على أن هذا النهج يمكن أن يكون أفضل من استخدام سلاسل بسيطة؟

إذا كان يعمل كما هو معلن ، فمن المؤكد أنه سيجعل الأمور أسهل بكثير للتصحيح.

3. كيف يمكنك تصميم واجهة برمجة التطبيقات؟

انظر ملاحظاتي في القسم التالي. أنا آخذ الأمثلة الخاصة بك ومكتبة .NET المرتبطة كنقطة انطلاق.

4. هل يمكنك استخدام هذه الأداة المساعدة الأنيقة في مشاريعك؟

غير محدد. ليس لدي مشكلة في العمل مع الإصدار الحالي من تعبيرات Cryptic بانتظام. وسأحتاج إلى أداة لتحويل التعبيرات العادية الموجودة إلى إصدار اللغة بطلاقة.

5. هل تعتقد أن هذا سيكون ممتعًا للتنفيذ؟ ؛)

سأستمتع بمستوى أعلى كيف ، من كتابة الكود الفعلي. وهو ما يفسر جدار النص الذي هو هذا الإجابة.


فيما يلي بعض المشكلات التي لاحظتها ، والطريقة التي سأتعامل بها معها.

بنية غير واضحة.

يبدو أن مثالك ينشئ regex عن طريق تسلسل الأوتار. هذا ليس قويا جدا. أعتقد أنه ينبغي إضافة هذه الطرق إلى كائنات السلسلة والأب/regex ، لأنها ستجعل التنفيذ والرمز نظافة. إلى جانب أنها تشبه الطريقة التي يتم بها تعريف التعبيرات العادية بشكل كلاسيكي.

لمجرد أنني لا أستطيع رؤيته يعمل بأي طريقة أخرى ، فإن بقية التعليقات التوضيحية الخاصة بي على المخطط المقترح سوف تفترض أن جميع الطرق تعمل على كائنات نمط وإرجاعها.

تعديل: يبدو أنني استخدمت الاتفاقيات التالية طوال الوقت. لذلك أوضحت لهم ونقلهم هنا.

  • أساليب مثيل: زيادة النمط. على سبيل المثال: التقاط ، التكرار ، انظر حول التأكيدات.

  • المشغلين: ترتيب العمليات. التناوب ، التسلسل

  • الثوابت: فئات الأحرف ، الحدود (في مكان w ، $ ، b ، إلخ)

كيف سيتم التعامل مع التقاط/التجميع؟

التقاط جزء كبير من التعبيرات العادية.

أرى كل كائن نمط يتم تخزينه داخليًا كمجموعة. (؟: نمط) من حيث بيرل. السماح برموز النمط ليتم خلطها بسهولة واختلاقها دون التدخل في قطع أخرى.

أتوقع أن يتم التقاط كطريقة مثيل على نمط ما. أخذ متغير لتخزين سلسلة المطابقة [s] في.

pattern.capture(variable) سوف تخزين نمط في المتغير. في حالة أن يكون الالتقاط جزءًا من التعبير الذي سيتم مطابقته عدة مرات ، يجب أن يحتوي المتغير على مجموعة من سلاسل جميع المباريات للنمط.

يمكن أن تكون اللغات بطلاقة غامضة للغاية.

اللغات بطلاقة ليست مناسبة تمامًا للطبيعة العودية للتعبيرات العادية. لذلك يجب الاعتبار لترتيب العمليات. فقط أساليب التسلسل معًا لا تسمح بتعبيرات منتظمة معقدة للغاية. بالضبط الموقف الذي ستكون فيه هذه الأداة مفيدة.

يفعل

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

ينتج /a*|b{2,5}/ أو /(a*|b){2,5}/ ?

كيف يمكن لهذا المخطط التعامل مع التناوب المتداخل؟ على سبيل المثال: /a*|b(c|d)|e/

أرى ثلاث طرق للتعامل مع التناوب في التعبيرات العادية

  1. كمشغل: pattern1 or pattern2 => pattern # /pattern1|pattern2/
  2. كطريقة الفصل: Pattern.or( pattern1, pattern2[, pattern3]*) => pattern # /pattern1|patern2|patern3|...|/
  3. كطريقة مثيل: pattern1.or(pattern2) => pattern # /pattern1|patern2/

أود التعامل مع التسلسل بنفس الطريقة.

  1. كمشغل: pattern1 + pattern2 => pattern # /pattern1pattern2/
  2. كطريقة الفصل: Pattern.concatenate( pattern1, pattern2[, pattern3]*) => pattern # /pattern1patern2patern3.../
  3. كطريقة مثيل: pattern1.then(pattern2) => pattern # /pattern1patern2/

كيفية تمديد الأنماط الشائعة الاستخدام

المخطط المقترح المستخدم .domain() الذي يبدو أنه regex شائع. لعلاج الأنماط المحددة للمستخدم كطرق لا تجعل من السهل إضافة أنماط جديدة. في لغة مثل مستخدمي Java للمكتبة ، سيتعين على الفصل تجاوز الفصل لإضافة طرق للأنماط الشائعة الاستخدام.

يتم تناول هذا من خلال اقتراحي لعلاج كل قطعة ككائن. يمكن إنشاء كائن نمط لكل إعادة استخدام شائعة الاستخدام مثل مطابقة مجال على سبيل المثال. بالنظر إلى أفكاري السابقة حول التقاطها ، لن يكون من الصعب أيضًا التأكد من أن التقاط أعمال متعددة من نفس النمط الشائع الذي يحتوي على قسم تم التقاطه.

يجب أن يكون هناك أيضًا ثوابت للأنماط التي تطابق فئات الشخصيات المختلفة.

عرض الصفر انظر حول التأكيدات

التوسع في أفكاري بأن جميع القطع يجب أن تكون متجانسة ضمنية. انظر حول التأكيدات لا ينبغي أن تكون صعبة للغاية مع طريقة مثيل.

pattern.zeroWidthLookBehind() سوف تنتج (?<patten).


الأشياء التي لا تزال بحاجة إلى النظر فيها.

  • Backreferences: نأمل ألا يكون الأمر صعبًا للغاية مع مناقشة الاستيلاء المسمى في وقت سابق
  • كيف تنفذها بالفعل. لم أقم بالتفكير الداخلي. إنه المكان الذي سيحدث فيه السحر الحقيقي.
  • الترجمة: يجب أن يكون هناك حقًا أداة ترجمة من وإلى Regexs الكلاسيكية (على سبيل المثال لهجة Perl) والمخطط الجديد. يمكن أن تكون الترجمة من المخطط الجديد جزءًا من الحزمة

وضع كل شيء معًا ، نسختي المقترحة من نمط يطابق عنوان البريد الإلكتروني:

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

بعد فوات الأوان ، يستعير مخططي بشدة من مقاربة مارتن فاولر في الاستخدام. على الرغم من أنني لم أكن أنوي أن تسير الأمور بهذه الطريقة ، إلا أنها بالتأكيد تجعل استخدام مثل هذا النظام أكثر قابلية للصيانة. كما أنه يعالج مشكلة أو اثنين مع نهج فاولر (أمر التقاط).

يمكن العثور على محاولتي المتواضعة جيثب. على الرغم من أنني لا أعتقد أن الأمر يستحق استخدامه للتعبيرات البسيطة ، إلا أنه يوفر مزايا بضع مزايا بصرف النظر عن تحسين قابلية القراءة:

  • يعتني بمطابقة قوسين
  • إنه يتعامل مع الهروب من جميع الشخصيات "الخاصة" التي يمكن أن تؤدي بسرعة إلى الجحيم الخلف

بعض الأمثلة البسيطة:

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

وعلى بعد أكثر تعقيدًا (والتي تتحقق أكثر أو أقل من عناوين البريد الإلكتروني):

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

إجابة قصيرة: لقد رأيت أنه اقترب من زاوية linting وتجميع ، والتي أعتقد أنها شيء يجب مراعاته في هذا.

إجابة طويلة: الشركة التي أعمل عليها تجعل محركات التعبير العادية القائمة على الأجهزة لتطبيقات تصفية محتوى المؤسسة. فكر في تشغيل تطبيقات مكافحة الفيروسات أو جدار الحماية بسرعة 20 جيجابايت/ثانية مباشرة في أجهزة توجيه الشبكة بدلاً من تناول دورات خادم أو معالج قيمة. معظم تطبيقات مكافحة الفيروسات أو مكافحة البريد العشوائي أو جدار الحماية هي مجموعة من تعبيرات Regex في القلب.

على أي حال ، فإن الطريقة التي يتم بها كتابة Regex لها تأثير كبير على أداء المسح. يمكنك كتابة regexs بعدة طرق مختلفة للقيام بنفس الشيء ، وسيكون بعضها أداء أسرع بشكل كبير. لقد كتبنا المترجمين والمضادات لعملائنا لمساعدتهم على الحفاظ على تعبيراتهم وضبطها.

بالعودة إلى سؤال البروتوكول الاختياري ، بدلاً من تحديد بناء جملة جديد بالكامل ، سأكتب مخططًا (آسف ، ملكنا الخاص) قطعه ولصق Regex في هذا الأمر سيؤدي إلى تحطيم Regex Legacy وإخراج "اللغة الإنجليزية بطلاقة" لفهم شخص ما بشكل أفضل. سأضيف أيضًا فحوصات الأداء النسبية والاقتراحات للتعديلات الشائعة.

الجواب القصير هو أن تحصل مرة واحدة إلى التعبيرات العادية (أو غيرها من مطابقة النقش أن يفعل الشيء نفسه) أن تكون طويلة بما فيه الكفاية أن يسبب مشكلة...ربما يجب عليك أن تنظر إذا كانوا الأداة المناسبة للحصول على وظيفة في المقام الأول.

بصراحة أي بطلاقة واجهة يبدو أنه سيكون من الصعب قراءة من معيار التعبير العادية.حقا قصيرة التعبير بطلاقة الإصدار هو مطول ، ولكن ليس طويلا ؛ انها قابلة للقراءة.ولكن ذلك هو التعبير العادية على ذلك مدة طويلة.

بالنسبة متوسطة الحجم العادي التعبير بطلاقة واجهة يصبح غير عملي;طويلة بما فيه الكفاية أنه من الصعب إن لم يكن من المستحيل أن تقرأ.

لفترة طويلة من التعبير العادي (أي عنوان بريد إلكتروني واحد) ، حيث التعبير العادي هو في الواقع من الصعب (إن لم يكن من المستحيل) أن يجيد الإصدار أصبح من المستحيل قراءة 10 صفحات مضت.

هل تعرف أي نهج مماثل للتعبيرات العادية؟

لا ، باستثناء الإجابة السابقة

هل توافق على أن هذا النهج يمكن أن يكون أفضل من استخدام سلاسل بسيطة؟

نوعًا ما - أعتقد أنه بدلاً من الأحرف المفردة لتمثيل بنيات ، يمكننا استخدام المزيد من الترميز الوصفي ، لكنني أشك في أنه سيجعل المنطق المعقد أكثر وضوحًا.

كيف يمكنك تصميم واجهة برمجة التطبيقات؟

قم بترجمة كل بنية إلى اسم طريقة ، واترك مكالمات الوظائف المتداخلة بحيث يكون من السهل جدًا اتخاذ سلسلة من الأسماء والبديل عنها.

أعتقد أن غالبية القيمة ستكون في تحديد مكتبة قوية من وظائف الأداة المساعدة ، مثل مطابقة "رسائل البريد الإلكتروني" ، "أرقام الهواتف" ، "الخطوط التي لا تحتوي على X" ، وما إلى ذلك يمكن تخصيصها.

هل يمكنك استخدام هذه الأداة المساعدة الأنيقة في مشاريعك؟

ربما - ولكن ربما فقط بالنسبة للأطول ، حيث سيكون من الأسهل تصحيح مكالمات وظائف التصحيح من تحرير سلسلة تصحيح الأخطاء ، أو عندما تكون هناك وظيفة فائدة لطيفة جاهزة للاستخدام.

هل تعتقد أن هذا سيكون ممتعًا للتنفيذ؟ ؛)

بالتاكيد!

رداً على الجزء الأخير من السؤال (عن مجد)

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

تطابق عناوين البريد الإلكتروني المتوافقة مع RFC: د

التعبير العادي هو وصف لآلة الحالة المحدودة. التمثيل النصي الكلاسيكي ليس سيئًا بالضرورة. إنه مضغوط ، إنه أمر لا يسرع نسبيًا ويتم تبنيه جيدًا إلى حد ما.

قد يكون التمثيل الأفضل هو مخطط انتقال الحالة ، ولكن من المحتمل أن يكون ذلك من الصعب استخدامه في التعليمات البرمجية المصدر.

يتمثل أحد الاحتمالات في بنائه من مجموعة متنوعة من كائنات الحاويات والمدمجة.

يتم ترك شيء ما على طول خط ما يلي (يحول هذا من الرمز الزائفة إلى اللغة التي يختارها كتمرين للحرص):

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

لاحظ أن ما ورد أعلاه سيصنف بشكل غير صحيح العديد من عناوين البريد الإلكتروني على أنها صالحة لا تتوافق مع القواعد النحوية التي يتعين عليهم اتباعها ، لأن هذه القواعد تتطلب أكثر من FSM بسيطة للتحليل الكامل. لا أعتقد أنه من الممكن تصنيف عنوان صالح على أنه غير صالح.

يجب أن تتوافق مع [^@]+@([A-ZA-Z0-9-]+.)+. ([A-ZA-Z0-9-]+)

4. هل يمكنك استخدام هذه الأداة المساعدة الأنيقة في مشاريعك؟

على الأرجح لا. أعتقد أن هذه حالة من استخدام الأداة المناسبة للوظيفة. هناك بعض الإجابات الرائعة هنا مثل: 1579202 من جيريمي شتاين. لقد "حصلت" على تعبيرات منتظمة مؤخرًا على مشروع حديث ووجدتها مفيدة للغاية كما هي ، وعندما تعلق بشكل صحيح ، تكون مفهومة إذا كنت تعرف بناء الجملة.

أعتقد أن جزء "معرفة بناء الجملة" هو ما ينشئ الناس إلى تعبيرات منتظمة ، لأولئك الذين لا يفهمون أنهم يبدون غامقًا ومُرضيًا ، لكنهم أداة قوية وفي علوم الكمبيوتر التطبيقية (على سبيل المثال برنامج الكتابة من أجل لقمة العيش) أشعر أن المهنيين الأذكياء يجب أن يكونوا قادرين على تعلم استخدامهم ولديهم بشكل مناسب.

كما يقولون "مع القوة العظمى تأتي مسؤولية كبيرة". لقد رأيت الناس يستخدمون تعبيرات منتظمة في كل مكان لكل شيء ، لكن استخدمه بحكمة من قبل شخص استغرق وقتًا لتعلم بناء الجملة تمامًا ، فهي مفيدة بشكل لا يصدق ؛ بالنسبة لي ، فإن إضافة طبقة أخرى من شأنها أن تهزم هدفها ، أو كحد أدنى يسلب قوتهم.

هذا فقط رأيي الخاص وأستطيع أن أفهم من أين يأتي الناس من من يرغب في إطار مثل هذا ، أو من يتجنب التعبيرات المنتظمة ، لكن لديّ صعوبة في سماع "التعبيرات العادية سيئة" من أولئك الذين لم يأخذوا الوقت لتعلمهم واتخاذ قرار مستنير.

لجعل الجميع سعداء (REGEX Masters and Fluid Interface) ، تأكد من أن واجهة السوائل يمكنها إخراج نمط Regex RAW مناسب ، وأيضًا أخذ regex منتظم باستخدام طريقة المصنع وإنشاء رمز السوائل لذلك.

يمكن العثور على ما تبحث عنه هنا:. إنه تعبير منتظم buillder يتبع نمط تصميم المعالج

لقد كان مؤخرًا هذه الفكرة نفسها.

فكرت في تنفيذها بنفسي ، ولكن بعد ذلك وجدت الانحدار اللفظي.

دعونا نقارن: لقد عملت كثيرًا مع (N) استفسارات السبات ، والتي يمكن اعتبارها أ طلِق رسم الخرائط إلى SQL. كنت (وما زلت) متحمسًا لهم ، لكن هل جعلوا استعلامات SQL أكثر وضوحًا؟ لا ، أكثر على عكس ذلك ، ولكن روز فائدة أخرى: أصبح من الأسهل بكثير بناء البيانات برمجيا ، لتصنيفها الفرعي وإنشاء تجريداتك الخاصة وما إلى ذلك.

ما أحصل عليه هو أن استخدام واجهة جديدة للغة معينة ، إذا تم القيام به بشكل صحيح ، يمكن أن يكون جديراً بالاهتمام ، لكن لا تفكر في ذلك بشدة. في كثير من الحالات ، لن يصبح القراءة أسهل (فئات شخصية الطرح المتداخلة ، ويلتقط في البحث ، إذا كان الفرع لتسمية بعض المفاهيم المتقدمة التي سيكون من الصعب الجمع بينها بطلاقة). ولكن في العديد من الحالات ، تفوق فوائد مرونة أكبر النفقات العامة المضافة لتعقيد بناء الجملة.

للإضافة إلى قائمة الأساليب البديلة المحتملة ولإخراج هذا من سياق Java فقط ، فكر في بناء جملة LINQ. إليك ما يمكن أن يبدو عليه (مفتعل قليلاً) (from, where و select هي الكلمات الرئيسية في 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 */

مجرد فكرة تقريبية ، وأنا أعلم. الشيء الجيد في LINQ هو أنه يتم فحصه بواسطة المترجم ، وهو نوع من اللغة بلغة ما. بشكل افتراضي ، يمكن أيضًا التعبير عن LINQ كناء على بناء جملة بالسلاسل بطلاقة ، مما يجعله ، إذا كان مصممًا جيدًا ، متوافقًا مع لغات OO الأخرى.

أقول اذهب لذلك ، أنا متأكد من أنه من الممتع التنفيذ.

أقترح استخدام نموذج الاستعلام (على غرار jQuery ، Django orm) ، حيث تقوم كل وظيفة بإرجاع كائن استعلام ، حتى تتمكن من تقليصها معًا.

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

أين chars محدد مسبقا لتناسب أي حرف.

or يمكن تحقيقها باستخدام الخيارات:

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

يمكن أن تكون الوسيطة إلى كل وظيفة سلسلة أو استعلام آخر. على سبيل المثال ، chars يمكن تعريف المتغير المذكور أعلاه على أنه استعلام:

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

وهكذا ، يمكنك الحصول على وظيفة "خام" تقبل سلسلة regex كمدخل إذا كان من الممكن استخدام نظام الاستعلام بطلاقة.

في الواقع ، يمكن لهذه الوظائف إعادة regex الخام فقط ، وتسلسلها ببساطة تسلسل هذه السلاسل regex الخام.

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

لست متأكدًا من أن استبدال regexp بأجهزة واجهة برمجة تطبيقات بطلاقة من شأنها أن تجلب الكثير.

لاحظ أنني لست معالج regexp (يجب أن أعيد قراءة المستند في كل مرة أحتاج إلى إنشاء regexp).

من شأن واجهة برمجة التطبيقات بطلاقة أن تجعل أي إعادة توصيل متوسطة التعقيد (دعنا نقول ~ 50 حرفًا) أكثر تعقيدًا مما هو مطلوب وليس أسهل في القراءة في النهاية ، على الرغم من أنه قد يحسن خلق من regexp في IDE ، وذلك بفضل إكمال الكود. لكن صيانة الكود تمثل عمومًا تكلفة أعلى من تطوير الكود.

في الواقع ، لست متأكدًا من أنه سيكون من الممكن أن يكون لديك واجهة برمجة تطبيقات ذكية بما يكفي لتوفير إرشادات كافية للمطور عند إنشاء RegexP جديد ، وعدم الحديث عن الحالات الغامضة ، كما هو مذكور في إجابة سابقة.

لقد ذكرت مثال regexp ل RFC. أنا متأكد بنسبة 99 ٪ (لا يزال هناك 1 ٪ من الأمل ؛-)) أن أي واجهة برمجة تطبيقات لن تجعل هذا المثال أبسط ، ولكن على العكس من ذلك سيجعله أكثر تعقيدًا للقراءة! هذا مثال نموذجي حيث لا تريد استخدام regexp على أي حال!

حتى فيما يتعلق بإنشاء regexp ، نظرًا لمشكلة الأنماط الغامضة ، فمن المحتمل أنه مع واجهة برمجة تطبيقات بطلاقة ، لن تأتي أبدًا مع التعبير الصحيح في المرة الأولى ، ولكن يجب أن تتغير عدة مرات حتى تحصل على ما تريده حقًا.

لا تخطئ ، أنا أحب واجهات بطلاقة ؛ لقد طورت بعض المكتبات التي تستخدمها ، وأنا أستخدم العديد من المكتبات الطرف الثالث بناءً عليها (على سبيل المثال لاختبار Java). لكنني لا أعتقد أنهم يمكن أن يكونوا المطرقة الذهبية لأي مشكلة.

إذا نظرنا إلى Java على وجه الحصر ، أعتقد أن المشكلة الرئيسية في Regexps هي الهروب الضروري من الخلف في جافا سلسلة الثوابت. هذه نقطة واحدة تجعل من الصعب للغاية إنشاء وفهم regexp في Java. وبالتالي ، فإن الخطوة الأولى لتعزيز Java regexp ستكون ، بالنسبة لي ، تغيير اللغة ، لوس أنجلوس, ، حيث لا تحتاج ثوابت السلسلة إلى الهروب.

حتى الآن سيكون هذا اقتراحي الوحيد لتحسين regexp في جافا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top