regex - example - regular expression شرح




استخدام التعبيرات العادية لتحليل HTML: لماذا لا؟ (12)

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

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

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

أعتقد أنني أقول أنها مقايضة. في بعض الأحيان قد لا يكون تنفيذ أو استخدام محلل صحيح - بالسهولة التي قد تكون - يستحق العناء إذا كانت الدقة غير حاسمة.

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

يبدو أن كل سؤال على stackoverflow حيث يستخدم السائل regex للاستيلاء على بعض المعلومات من HTML سيكون حتمًا "إجابة" تقول أنه لا يستخدم regex لتحليل HTML.

لما لا؟ أنا على دراية بأن هناك موزعي HTML "حقيقيين" للاقتباس من هناك مثل الشوربة الجميلة ، وأنا متأكد من أنها قوية ومفيدة ، ولكن إذا كنت تفعل شيئًا بسيطًا وسريعًا أو متسخًا ، فلماذا يزعج استخدام شيء معقد للغاية عندما تعمل بعض العبارات regex على ما يرام؟

علاوة على ذلك ، هل هناك شيء أساسي لا أفهمه حول التعبير العادي الذي يجعلهم خيارًا سيئًا للتحليل بشكل عام؟


(من http://htmlparsing.com/regexes )

لنفترض أنك حصلت على ملف HTML حيث تحاول استخراج عناوين URL من <img>.

<img src="http://example.com/whatever.jpg">

لذلك تكتب تعبيرًا مثل هذا في Perl:

if ( $html =~ /<img src="(.+)"/ ) {
    $url = $1;
}

في هذه الحالة ، سيحتوي $url بالفعل على http://example.com/whatever.jpg . ولكن ما يحدث عندما تبدأ في الحصول على HTML مثل هذا:

<img src='http://example.com/whatever.jpg'>

أو

<img src=http://example.com/whatever.jpg>

أو

<img border=0 src="http://example.com/whatever.jpg">

أو

<img
    src="http://example.com/whatever.jpg">

أو تبدأ في الحصول على نتائج كاذبة من

<!-- // commented out
<img src="http://example.com/outdated.png">
-->

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


أعتقد أن الإجابة تكمن في نظرية الحساب. بالنسبة إلى لغة يتم تحليلها باستخدام regex ، يجب أن يكون تعريفها "عادي" ( link ). لغة HTML ليست لغة عادية لأنها لا تفي بعدد من المعايير الخاصة بلغة عادية (كثيرًا ما يتعلق بالعديد من مستويات التداخل الكامنة في كود HTML). إذا كنت مهتمًا بنظرية الحساب ، أوصي this الكتاب.


أنت ، تعرف ... هناك الكثير من عقلية أنت لا تستطيع أن تفعل ذلك وأعتقد أن كل شخص على جانبي السياج على صواب وما هو خطأ. يمكنك فعل ذلك ، ولكن الأمر يتطلب معالجة أكثر بقليل من مجرد تشغيل تعبير واحد ضدها. خذ this (كتبت هذا داخل ساعة) كمثال. يفترض أن HTML صحيح تمامًا ، ولكن استنادًا إلى اللغة التي تستخدمها لتطبيق التعبير المعتاد المذكور ، يمكنك إجراء بعض التثبيت لـ HTML للتأكد من نجاحه. على سبيل المثال ، إزالة علامات الإغلاق غير المفترض وجودها: </img> على سبيل المثال. بعد ذلك ، أضف شرطة مائلة HTML واحدة مائلة للأمام إلى عناصر مفقودة ، وما إلى ذلك.

سأستخدم هذا في سياق كتابة مكتبة تسمح لي بإجراء عملية استرداد عنصر HTML مماثلة لـ [x].getElementsByTagName() ، على سبيل المثال. سأقوم فقط بتوصيف الوظائف التي كتبتها في قسم DEFINE من regex واستخدمها للتدرج داخل شجرة عناصر ، واحدة في الوقت المناسب.

إذن ، هل سيكون هذا هو الجواب النهائي 100٪ للتحقق من صحة HTML؟ لا ، لكنها بداية ومع المزيد من العمل ، يمكن القيام بها. ومع ذلك ، فإن محاولة تنفيذ ذلك من خلال تنفيذ واحد للتعبير العادي ليست عملية ، ولا تتسم بالكفاءة.


بقدر ما يحدث التحليل ، يمكن أن تكون التعبيرات العادية مفيدة في مرحلة "التحليل المعجمى" (lexer) ، حيث يتم تقسيم المدخلات إلى رموز. إنها أقل فائدة في مرحلة "إنشاء شجرة تحليل" فعلية.

بالنسبة إلى محلل HTML ، أتوقع أن يقبل فقط HTML جيدًا ويتطلب قدرات خارج ما يمكن أن يفعله التعبير العادي (لا يمكنهم "العد" والتأكد من أن عدد معين من عناصر الافتتاح يكون متوازنًا بنفس العدد من إغلاق العناصر).


تكمن المشكلة في أن معظم المستخدمين الذين يطرحون سؤالًا يتعلق بـ HTML و regex يقومون بذلك لأنهم لا يستطيعون العثور على تعبير منطقي ناجح. ثم على المرء أن يفكر فيما إذا كان كل شيء سيكون أسهل عند استخدام محلل DOM أو SAX أو شيء مماثل. يتم تحسينها وبناءها لغرض العمل مع هياكل وثيقة تشبه XML.

بالتأكيد ، هناك مشاكل يمكن حلها بسهولة مع التعبيرات العادية. لكن التركيز يكمن في سهولة .

إذا كنت تريد فقط العثور على جميع عناوين URL التي تبدو مثل http://.../ فأنت بخير مع regexps. ولكن إذا كنت ترغب في العثور على جميع عناوين URL الموجودة في a-element التي تحتوي على "mylink" للفصل ، فمن الأفضل استخدام محلل مناسب.


سببان سريعان:

  • كتابة تعبير عادي يمكن أن يصمد أمام المدخلات الخبيثة صعب ؛ بطريقة أكثر صعوبة من استخدام أداة سابقة الإعداد
  • كتابة تعبير منطقي يمكن أن يعمل مع الترميز المضحك الذي سوف يكون من الصعب حتما مع أنه صعب ؛ بطريقة أكثر صعوبة من استخدام أداة سابقة الإعداد

فيما يتعلق بملاءمة regexes للتحليل بشكل عام: فهي ليست مناسبة. هل سبق لك أن رأيت أنواع من regexes كنت بحاجة إلى تحليل معظم اللغات؟


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

على سبيل المثال ، يعد خطأ لعلامات <form> ليتم تداخلها ؛ إذا كانت صفحة الويب تعمل بشكل صحيح ، فإن استخدام تعبير عادي للاستيلاء على <form> سيكون معقولًا تمامًا.

قمت مؤخرًا بإجراء بعض عمليات تجريف الويب باستخدام السيلنيوم فقط والتعبيرات العادية. ابتعدت عنه لأن البيانات التي أردت وضعها في <form> ، ووضعها في شكل جدول بسيط (حتى أتمكن من الاعتماد على <table> و <tr> و <td> حتى لا تكون متداخلة-- وهو في الواقع غير عادي للغاية). لقد كانت التعبيرات العادية ، إلى حد ما ، ضرورية تقريبا ، لأن بعض البنية التي احتاجت إلى الوصول إليها كانت مفصولة بالتعليقات. (يمكن أن تعطيك الشوربة الجميلة التعليقات ، ولكن كان من الصعب الحصول على كتل <!-- BEGIN --> و <!-- END --> باستخدام الشوربة الجميلة.)

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



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

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


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


هناك بالتأكيد حالات يكون فيها استخدام تعبير منتظم لتحليل بعض المعلومات من HTML هو الطريقة الصحيحة - فهي تعتمد كثيرًا على الموقف المحدد.

توافق الآراء أعلاه هو أنه بشكل عام فكرة سيئة. ولكن إذا كان هيكل HTML معروفًا (ومن غير المرجح أن يتغير) ، فإنه لا يزال نهجًا صالحًا.





html-parsing