مقدمة
في الآونة الأخيرة ، وجدت أن أداء الانتظام في JavaScript في بعض الأماكن يختلف إلى حد ما عن تلك الموجودة في اللغات أو الأدوات الأخرى ، وهو بديل نسبيًا. على الرغم من أنه من المستحيل تقريبًا أن تكتبها ولا يمكنك استخدام القواعد التي ذكرتها أدناه ، إلا أنه من الجيد فهمها بعد كل شيء.
يتم تنفيذ أمثلة الكود في هذه المقالة في بيئة JavaScript متوافقة مع ES5. وهذا يعني أن الأداء في الإصدارات قبل IE9 ، من المحتمل أن يكون الإصدارات حول FX4 ، وما إلى ذلك مختلفة عما ذكرته أدناه.
1. فئة الأحرف الفارغة
تسمى فئة الأحرف التي لا تحتوي على أي [] فئة empty char class فارغة. أعتقد أنك لم تسمع من قبل الآخرين يسميونها لأن طريقة الكتابة هذه غير قانونية ، وجميع المستندات والدروس التعليمية لا تتحدث عن بناء جملة غير قانوني. اسمحوا لي أن أوضح كيف أن اللغات أو الأدوات الأخرى الإبلاغ عن هذا الخطأ:
$ echo | grep '[]' grep: لا مثيل لها [أو [^$ echo | SED '/[]/' SED: -e التعبير #1 ، الحرف 4: العنوان غير المنتهي التعبير العادي $ echo | awk '/[]/' awk: cmd. السطر: 1: /[] /awk: cmd. السطر: 1: ^ regexpawk غير المنتهية: cmd. السطر: 1: خطأ: لا مثيل له [أو [^:/[] // $ echo | perl -ne '/[]/' لا مثيل لها [في regex ؛ تميزت بـ <-هنا في m/ [<-هنا]/ في الخط 1. $ echo | ruby -ne '/[]/' -e: 1: الفئة char فارغة:/[]/$ python -c 'import re ؛ re.match ("[]" ، "")' traceback (أحدث مكالمة أخيرة): ملف "<string>" ، السطر 1 ، في <module> file "e: /python/lib/Re.py" ، السطر 137 ، "e: /python/lib/re.py" ، السطر 244 ، في _Compile refr error ، v # invalid expressionre_constants.error: نهاية غير متوقعة للتعبير العادي في JavaScript ، تعد فئة الأحرف الفارغة مكونًا قانونيًا عاديًا ، لكن تأثيره "لا يتطابق أبدًا" ، أي أن كل شيء سيفشل. إنه يعادل تأثير (empty negative lookahead)(?!) :
JS> "anhay/n" .match (/[]/g) // فئة حرف خالية ، لا تتطابق أبدًا
من الواضح أن هذا النوع من الأشياء عديم الفائدة في جافا سكريبت.
2. نفي فئة الأحرف الفارغة
تسمى فئات الأحرف السلبية التي لا تحتوي على أي أحرف فئة char الفارغة السلبية أو فئة char السلبية الفارغة ، لأن هذا الاسم "تم إنشاؤه ذاتيا" ومماثلة لفئة الأحرف الفارغة المذكورة أعلاه. طريقة الكتابة هذه غير قانونية أيضًا بلغات أخرى:
$ echo | grep '[^]' grep: Unfated [أو [^$ echo | sed '/[^]/' sed: -e التعبير #1 ، الحرف 5: العنوان غير المنتهي التعبير العادي $ echo | awk '/[^]/' awk: cmd. السطر: 1: /[^] /awk: cmd. السطر: 1: ^ regexpawk غير المنتهية: cmd. السطر: 1: خطأ: لا مثيل له [أو [^:/[^] // $ echo | perl -ne '/[^]/' Unfated [in regex ؛ تميزت بـ <-هنا في m/ [<-هنا ^]/ at line 1. $ echo | ruby -ne '/[^]/' -e: 1: char -class فارغ:/[^]/$ python -c 'ret re ؛ re ملف "e: /python/lib/re.py" ، السطر 244 ، في _compile refr error ، v # invalid explider_constants.error: نهاية غير متوقعة للتعبير العادي $
في JavaScript ، يعد نفي فئة الأحرف الفارغة مكونًا عاديًا قانونيًا. تأثيره هو مجرد عكس تأثير فئة الأحرف الفارغة. يمكن أن يتطابق مع أي حرف ، بما في ذلك الخط الجديد "/n" ، أي أنه يعادل المشترك [/s/S] و [/w/W] :
js> "anhow/n" .match (/[^]/g) // neizontal charaction ، تطابق أي حرف ["w" ، "h" ، "a" ، "t" ، "e" ، "v" ، "e" ، "r" ، "r" ، " "T" ، "E" ، "V" ، "E" ، "R" ، "/N"]
تجدر الإشارة إلى أنه لا يمكن تسميته "انتظام مطابقة دائم" ، لأن فئة الأحرف يجب أن يكون لها شخصية لتتناسب معها. إذا كانت السلسلة المستهدفة فارغة أو تم استهلاكها بواسطة الانتظام اليسرى ، فسوف تفشل المباراة ، على سبيل المثال:
js> /abc budap ^/.test("abc ") // لا توجد أحرف بعد C ، وفشل المطابقة.إذا كنت تريد معرفة "قواعد المطابقة الدائمة" الحقيقية ، فيمكنك الاطلاع على مقال قمت بترجمته من قبل: قواعد "فارغة"
3. [] و [^]]
هذا بسيط نسبيًا ، أي: في التعبيرات المنتظمة لـ Perl وبعض أوامر Linux الأخرى ، إذا كانت فئة الأحرف [] تحتوي على شريحة مربعة اليمنى مباشرة بعد []] المربعة اليسرى مباشرة ، فسيتم اعتبار الشريحة المربعة اليمنى شخصية طبيعية ، أي ، يمكن أن تتطابق فقط "]". في JavaScript ، سيتم التعرف على هذا الانتظام على أنه فئة حرف فارغة تليها شريحة مربعة اليمنى ، ولن تتطابق فئة الأحرف الفارغة لأي شيء .[^]] متشابه: في JavaScript ، يطابق شخصية تعسفية (فئة شخصية خالية سلبية) تليها قوس مربع يمين ، مثل "a]","b]" ، بينما في لغات أخرى ، يطابق أي شخصيات غير].
$ perl -e 'print "]" = ~/[]]/' 1 $ js -e 'print (/[]]/. test ("])" false $ perl -e' print "x" = ~/[^]]/'1 $ js -e' print (/[^]]/. test ("x")4. $ مرساة نقطة
يعتقد بعض المبتدئين أن $ يطابق شخصية الخط الجديد "/n" ، وهو خطأ كبير. $ هو تأكيد عرض الصفر ، من المستحيل مطابقة شخصية حقيقية ، ويمكنه فقط مطابقة موقع واحد. الفرق الذي أريد أن أتحدث عنه يحدث في وضع غير متجانس: قد تعتقد أنه في الوضع غير المتدني ، لا يتطابق $ مع الموقف بعد الحرف الأخير؟ في الواقع ليس بهذه البساطة. في معظم اللغات الأخرى ، إذا كانت الحرف الأخير في السلسلة الهدف هي الحرف الجديد "/n" ، فسيتطابق $ أيضًا مع الموضع قبل الخط الجديد ، أي أن المواقع على الجانبين اليسرى واليمين لكسر الخط في النهاية. العديد من اللغات لديها اثنين من الترميز /z و /z. إذا كنت تعرف الفرق بينهما ، فيجب عليك أن تفهم أنه في لغات أخرى (Perl ، Python ، PHP ، Java ، C#...) ، فإن $ في وضع غير Multi-line يعادل /z ، بينما في JavaScript ، فإن $ في وضع غير Multi-line يعادل /z (سوف يتطابق فقط مع المركز الأخير ، وبغض النظر عما إذا كانت الشخصية الأخيرة هي الخط الجديد). Ruby هي حالة خاصة لأنها تتخلف عن وضع متعدد الخطوط. سوف يتطابق $ في الوضع متعدد الخطوط مع كل سطر جديد ، وبالطبع سيتضمن أيضًا كسر الخط الذي قد يظهر في النهاية. يتحدث كتاب يو شنغ "المبادئ التوجيهية العادية" عن هذه النقاط.
$ perl -e 'print "anhay/n" = ~ s/$/replace character/rg' // global replace anhafer anhafer is $ js -e print (anhow/n ".
5. نقطة metacharacter "."
في تعبيرات منتظمة في JavaScript ، النقطة metacharacter "." يمكن أن تتطابق مع جميع الأحرف باستثناء أربع مخططات خطوط ( /R-Carriage Return ، /N-Line Newline ، /u2028-Line Siprorator ، /U2029-Peragraph Sipreator) ، بينما سيتم استبعاد خط Newline /N Line Newline فقط.
6. اقتبس إلى الأمام
نعلم جميعًا أن هناك مرجعًا خلفيًا بشكل منتظم ، أي مرجع رقم خلفي خلفي إلى السلسلة التي تتوافق مع مجموعة الالتقاط السابقة. والغرض من ذلك هو مطابقة مرة أخرى أو كنتيجة بديلة (/ تصبح $). ولكن هناك حالة خاصة أنه إذا لم تبدأ مجموعة الالتقاط المرجعية (يتم تحديد الشريحة اليسرى) ، فإنها تستخدم مرجع الخلفي ، ماذا سيحدث؟ على سبيل المثال ، العادية /(/2(a)){2}/ ، (أ) هي مجموعة الالتقاط الثانية ، ولكن يتم استخدام النتيجة المطابقة لها على الجانب الأيسر. نحن نعلم أن المباريات العادية من اليسار إلى اليمين. هذا هو أصل مرجع العنوان إلى الأمام في هذا القسم. إنه ليس مفهومًا صارمًا. لذا الآن تفكر في الأمر ، ماذا ستعود رمز JavaScript التالي:
JS>/(/2 (a)) {2}/. exec ("aaa") ؟؟؟قبل الإجابة على هذا السؤال ، دعونا نلقي نظرة على الأداء بلغات أخرى. وبالمثل ، في لغات أخرى ، فإن الكتابة بهذه الطريقة غير صالحة بشكل أساسي:
$ echo aaa | grep '(/2 (a)) {2}' grep: مرجع خلفي غير صالح $ echo aaa | sed -r '/(/2 (a)) {2}/' sed: -e التعبير #1 ، الحرف 12: مرجع خلفي غير قانوني $ echo aaa | awk '/(/2 (a)) {2}/' $ echo aaa | perl -ne 'print/(/2 (a)) {2}/' $ echo aaa | ruby -ne 'print $ _ = ~/(/2 (a)) {2}/' $ python -c 'import re ؛ print re.match ("(/2 (a)) {2}" ، "aaa") "لا شيءلا يوجد خطأ في AWK لأن AWK لا يدعم هذا المؤتمر الخلفي ، و /2 يتم تفسيره على أنه حرف مع رمز ASCII 2. ومع ذلك ، لا يوجد خطأ في Perl Ruby Python. لا أعرف لماذا يجب أن يتعلم بيرل هذا التصميم ، لكن التأثيرات هي نفسها. في هذه الحالة ، من المستحيل مطابقة بنجاح.
في JavaScript ، لا يقتصر الأمر على الإبلاغ عن خطأ ، ولكن يمكن أن يطابقه أيضًا بنجاح. دعونا نرى أن الإجابة هي نفسها التي فكرت بها للتو:
js> /(/2(a) {2 )/.exec("aaa") budapidisa "،" a "،" a "] لمنعك من نسيان النتيجة التي يتم إرجاعها بواسطة طريقة exec ، دعني أقول. العنصر الأول هو سلسلة المطابقة الكاملة ، أي RegExp["$&"] ، تليها محتوى كل مجموعة التقاط ، أي RegExp.$1 و RegExp.$2. لماذا يمكن أن تكون المطابقة ناجحة؟ ما هي عملية المطابقة؟ ما أفهمه هو:
أولاً ، ندخل مجموعة الالتقاط الأولى (الأقصى اليسرى) ، حيث تكون المباراة الأولى الصالحة هي /2 ، ولكن في هذا الوقت لم تكن مجموعة الالتقاط الثانية (أ) في الجولة ، وبالتالي فإن قيمة RegExp.$2 لا تزال undefined ، SO /2 تطابق شخصية فارغة على يسار الأول في السلسلة المستهدفة ، أو "وضع" ، فقط ^ Zero-Width. النقطة المهمة هي أن المباراة ناجحة. استمر في الذهاب ، ثم تتوافق مجموعة الالتقاط الثانية (A) مع أول A في السلسلة المستهدفة ، ويتم تعيين قيمة RegExp.$2 أيضًا إلى "A" ، ثم تنتهي مجموعة التقاط الأولى (أقصى اليمين في أقصى اليمين في أقصى اليمين) ، وقيمة RegExp.$1 هي أيضًا ". ثم هناك الكمية {2} ، أي بعد الأول A في السلسلة الهدف ، يتم بدء جولة جديدة من مطابقة العادية (/2(a)) . النقطة الرئيسية هنا: قيمة RegExp.$2 هي أن قيمة /2 تتطابق أو هي القيمة المخصصة في نهاية الجولة الأولى من مطابقة "A". الجواب هو: "لا" ، وقيم RegExp.$1 و RegExp.$2 على أنها undefined ، و /1 و /2 ستكون هي نفسها في المرة الأولى ، مطابقة بنجاح شخصية فارغة (أي ما يعادل أي تأثير ، سواء كانت مكتوبًا أم لا). تتم مطابقة الثانية A في السلسلة الهدف بنجاح ، ويصبح قيم RegExp.$1 و RegExp.$2 "A" مرة أخرى ، تصبح قيمة RegExp["$&"] سلسلة مطابقة كاملة ، أول اثنين A: "AA".
في الإصدارات السابقة من Firefox (3.6) ، لن تقوم إعادة تطابق الكميات بمسح قيمة المجموعة التي تم التقاطها الحالية ، بحيث تكون ، في الجولة الثانية من المباريات ، /2 ستطابق الثاني A ، وبالتالي:
js> /(/2(a) {2 )/.exec("aaa") budapidisaaa "،" a "]بالإضافة إلى ذلك ، تعتمد نهاية مجموعة الالتقاط على ما إذا كانت القوس الختامي مغلقًا. على سبيل المثال ،/(a/1) {3}/. على الرغم من أن مجموعة الالتقاط الأولى بدأت تتطابق مع /1 ، إلا أنها لم تنته بعد. هذا أيضًا مرجع أمامي ، لذا فإن المباراة بين /1 لا تزال فارغة:
js> /(a/1) {3 )/.exec("aaa") budapidisaaa "،" a "]مثال آخر:
JS> /(؟:(F)(o)(o)| ((((((((((erensmense yonderensity your.exec w.exec (
* هو الكمي. بعد الجولة الأولى من المطابقة: $ 1 هو "F" ، 2 دولار هو "O" ، 3 دولارات هو "O" ، 4 دولارات غير محددة ، 5 دولارات undefined ، و 6 دولارات undefined .
في بداية الجولة الثانية من المباريات: يتم إعادة تعيين جميع القيم التي تم التقاطها إلى undefined .
بعد الجولة الثانية من المباريات: 1 دولار undefined ، 2 دولار undefined ، 3 دولارات undefined ، 4 دولارات هي "B" ، 5 دولارات "A" ، و 6 دولارات "R".
ويتم تعيينه على أنه "foobar" ، وينتهي المباراة.
لخص
ما سبق هو المحتوى الكامل الذي يلخص الاختلافات بين انتظام JavaScript ولغات أخرى. آمل أن يكون محتوى هذه المقالة مفيدًا لدراسة الجميع والعمل.