Regex لمطابقة جميع علامات HTML باستثناء <p> و </p>

StackOverflow https://stackoverflow.com/questions/29869

  •  09-06-2019
  •  | 
  •  

سؤال

أحتاج إلى مطابقة جميع العلامات وإزالتها باستخدام تعبير عادي في Perl.لدي ما يلي:

<\\??(?!p).+?>

ولكن هذا لا يزال يتطابق مع الإغلاق </p> بطاقة شعار.هل هناك أي تلميح حول كيفية المطابقة مع علامة الإغلاق أيضًا؟

لاحظ أن هذا يتم تنفيذه على xhtml.

هل كانت مفيدة؟

المحلول 3

خطرت لي هذه:

<(?!\/?p(?=>|\s.*>))\/?.*?>

x/
<           # Match open angle bracket
(?!         # Negative lookahead (Not matching and not consuming)
    \/?     # 0 or 1 /
    p           # p
    (?=     # Positive lookahead (Matching and not consuming)
    >       # > - No attributes
        |       # or
    \s      # whitespace
    .*      # anything up to 
    >       # close angle brackets - with attributes
    )           # close positive lookahead
)           # close negative lookahead
            # if we have got this far then we don't match
            # a p tag or closing p tag
            # with or without attributes
\/?         # optional close tag symbol (/)
.*?         # and anything up to
>           # first closing tag
/

سيتعامل هذا الآن مع علامات p مع السمات أو بدونها وعلامات الإغلاق p، ولكنه سيطابق العلامات السابقة والمشابهة، مع السمات أو بدونها.

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

نصائح أخرى

اذا أنت يصر عند استخدام regex، سيعمل شيء مثل هذا في معظم الحالات:

# Remove all HTML except "p" tags
$html =~ s{<(?>/?)(?:[^pP]|[pP][^\s>/])[^>]*>}{}g;

توضيح:

s{
  <             # opening angled bracket
  (?>/?)        # ratchet past optional / 
  (?:
    [^pP]       # non-p tag
    |           # ...or...
    [pP][^\s>/] # longer tag that begins with p (e.g., <pre>)
  )
  [^>]*         # everything until closing angled bracket
  >             # closing angled bracket
 }{}gx; # replace with nothing, globally

ولكن حقًا، وفر على نفسك بعض الصداع واستخدم المحلل اللغوي بدلاً من ذلك.يحتوي CPAN على العديد من الوحدات المناسبة.فيما يلي مثال باستخدام HTML::TokeParser الوحدة التي تأتي مع القدرة للغاية HTML::محلل توزيع شبكة الاتصال المركزية:

use strict;

use HTML::TokeParser;

my $parser = HTML::TokeParser->new('/some/file.html')
  or die "Could not open /some/file.html - $!";

while(my $t = $parser->get_token)
{
  # Skip start or end tags that are not "p" tags
  next  if(($t->[0] eq 'S' || $t->[0] eq 'E') && lc $t->[1] ne 'p');

  # Print everything else normally (see HTML::TokeParser docs for explanation)
  if($t->[0] eq 'T')
  {
    print $t->[1];
  }
  else
  {
    print $t->[-1];
  }
}

HTML::محلل يقبل الإدخال في شكل اسم ملف، أو مقبض ملف مفتوح، أو سلسلة.لف الكود أعلاه في مكتبة وجعل الوجهة قابلة للتكوين (أي ليس فقط printكما في ما سبق) ليس بالأمر الصعب.ستكون النتيجة أكثر موثوقية وقابلية للصيانة وربما أسرع أيضًا (يستخدم HTML::Parser واجهة خلفية تعتمد على لغة C) من محاولة استخدام التعبيرات العادية.

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

على سبيل المثال، هذا:

<HTML /
  <HEAD /
    <TITLE / > /
    <P / >

هو مستند HTML كامل وجيد الصياغة وصالح بنسبة 100%.(حسنًا، إنه يفتقد إعلان DOCTYPE، ولكن بخلاف ذلك ...)

وهو يعادل لغويا

<html>
  <head>
    <title>
      &gt;
    </title>
  </head>
  <body>
    <p>
      &gt;
    </p>
  </body>
</html>

لكنها مع ذلك لغة HTML صالحة وسيتعين عليك التعامل معها.أنت استطاع, ، بالطبع، ابتكر تعبيرًا عاديًا لتحليله، ولكن كما اقترح آخرون بالفعل، فإن استخدام محلل HTML الفعلي هو أسهل بكثير.

لست متأكدًا من سبب رغبتك في القيام بذلك - فالتعبير العادي لتطهير HTML ليس دائمًا أفضل طريقة (عليك أن تتذكر تنظيف السمات وما شابه ذلك، وإزالة جافا سكريبت:hrefs وما شابه)...ولكن، تعبير عادي لمطابقة علامات HTML التي ليست كذلك <p></p>:

(<[^pP].*?>|</[^pP]>)

مطول:

(
    <               # < opening tag
        [^pP].*?    # p non-p character, then non-greedy anything
    >               # > closing tag
|                   #   ....or....
    </              # </
        [^pP]       # a non-p tag
    >               # >
)

لقد استخدمت Xetius regex وهو يعمل بشكل جيد.باستثناء بعض العلامات المرنة التي يمكن أن تكون:
مع عدم وجود فراغات في الداخل.لقد حاولت إصلاحه بطريقة بسيطة ? بعد ويبدو أنه يعمل:

<(?!\/?p(?=>|\s?.*>))\/?.*?>

أنا أستخدمه لمسح العلامات من نص html المرن، لذلك أضفت أيضًا المزيد من العلامات المستثناة:

<(?!\/?(p|a|b|i|u|br)(?=>|\s?.*>))\/?.*?>

نظرًا لأن HTML ليست لغة عادية، فلا أتوقع أن يقوم التعبير العادي بعمل جيد جدًا في مطابقتها.ربما يكونون على مستوى هذه المهمة (على الرغم من أنني لست مقتنعًا بذلك)، لكنني سأفكر في البحث في مكان آخر؛أنا متأكد من أن لغة Perl يجب أن تحتوي على بعض المكتبات الجاهزة للتعامل مع HTML.

على أي حال، أعتقد أن ما تريد مطابقته هو </?(p.+|.*)(\s*.*)> غير جشع (لا أعرف تقلبات بناء جملة regexp الخاص بـ Perl لذا لا يمكنني المساعدة إضافي).أفترض أن \s يعني مسافة بيضاء.ربما لا.وفي كلتا الحالتين، فأنت تريد شيئًا يطابق السمات التي يتم إزاحتها من اسم العلامة بمسافة بيضاء.ولكن الأمر أكثر صعوبة من ذلك، حيث يقوم الأشخاص غالبًا بوضع أقواس زاوية غير قابلة للإلغاء داخل النصوص والتعليقات وربما حتى قيم السمات المقتبسة، والتي لا تريد مطابقتها معها.

لذلك كما قلت، لا أعتقد حقًا أن التعبيرات العادية هي الأداة المناسبة لهذه المهمة.

نظرًا لأن HTML ليست لغة عادية

HTML ليس كذلك ولكن علامات HTML موجودة ويمكن وصفها بشكل مناسب بواسطة التعبيرات العادية.

بافتراض أن هذا سيعمل في PERL كما هو الحال في اللغات التي تدعي أنها تستخدم بناء الجملة المتوافق مع PERL:

/<\/?[^p][^>]*>/

يحرر:

لكن هذا لن يتطابق مع أ <pre> أو <param> العلامة، للأسف.

ربما هذا؟

/<\/?(?!p>|p )[^>]+>/

ينبغي أن تغطي <p> العلامات التي لها سمات أيضًا.

قد ترغب أيضًا في السماح بمسافة بيضاء قبل الحرف "p" في العلامة p.لست متأكدًا من عدد المرات التي ستواجه فيها هذا الأمر، ولكن < p> هو HTML صالح تمامًا.

يمكن جعل التعبير العادي الأصلي يعمل بجهد قليل جدًا:

 <(?>/?)(?!p).+?>

وكانت المشكلة أن /؟(أو \؟) تخلى عما طابقه عندما فشل التأكيد الذي يليه.إن استخدام مجموعة غير متراجعة (؟>...) حولها يحرص على عدم تحرير الشرطة المائلة المطابقة أبدًا، لذلك يتم تثبيت التأكيد (؟!p) دائمًا في بداية نص العلامة.

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

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

مع كل إخلاءات المسؤولية حول استخدام التعبير العادي لتحليل HTML، إليك طريقة بسيطة للقيام بذلك.

#!/usr/bin/perl
$regex = '(<\/?p[^>]*>)|<[^>]*>';
$subject = 'Bad html <a> </I> <p>My paragraph</p> <i>Italics</i> <p class="blue">second</p>';
($replaced = $subject) =~ s/$regex/$1/eg;
print $replaced . "\n";

انظر الى هذا عرض حي

مرجع

كيفية مطابقة النمط إلا في المواقف s1، s2، s3

كيفية مطابقة النمط ما لم...

جرب هذا، يجب أن يعمل:

/<\/?([^p](\s.+?)?|..+?)>/

توضيح:فهو يطابق إما حرفًا واحدًا باستثناء "p"، متبوعًا بمسافة بيضاء اختيارية والمزيد من الأحرف، أو أحرف متعددة (اثنان على الأقل).

/يحرر:لقد أضفت القدرة على التعامل مع السمات في p العلامات.

ربما ينبغي عليك أيضًا إزالة أي سمات من العلامة <p>، حيث يمكن لأي شخص سيئ أن يفعل شيئًا مثل:

<p onclick="document.location.href='http://www.evil.com'">Clickable text</p>

أسهل طريقة للقيام بذلك هي استخدام التعبير العادي الذي يقترحه الأشخاص هنا للبحث عن علامات &ltp> ذات السمات، واستبدالها بعلامات <p> بدون سمات.فقط ابقا في مكان امن.

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