سؤال

أحاول استخراج سمات مرساة الوسم (<a>).حتى الآن لدي هذا التعبير:

(?<name>\b\w+\b)\s*=\s*("(?<value>[^"]*)"|'(?<value>[^']*)'|(?<value>[^"'<> \s]+)\s*)+

الذي يعمل في سلاسل مثل

<a href="test.html" class="xyz">

و (علامات الاقتباس المفردة)

<a href='test.html' class="xyz">

ولكن ليس عن سلسلة بدون علامات الاقتباس:

<a href=test.html class=xyz>

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

وذلك بفضل!

تحديث: شكرا لجميع التعليقات الجيدة والمشورة حتى الآن.هناك شيء واحد أنا لم أذكر:أنا للأسف إلى تصحيح/تعديل التعليمات البرمجية ليست مكتوبة من قبل نفسي.وليس هناك الوقت/المال إلى كتابة هذه الاشياء من أسفل إلى أعلى.

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

المحلول

إذا كان لديك عنصر مثل

<name attribute=value attribute="value" attribute='value'>

هذا regex يمكن استخدامها للعثور على التوالي كل سمة اسم و قيمة

(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?

تطبق على:

<a href=test.html class=xyz>
<a href="test.html" class="xyz">
<a href='test.html' class="xyz">

سيكون العائد:

'href' => 'test.html'
'class' => 'xyz'

ملاحظة: هذا لا يعمل مع الرقمية قيم السمة مثلا <div id="1"> لن تعمل.

نصائح أخرى

على الرغم من أن المشورة لا إلى تحليل HTML عن طريق regexp صالح هنا هو التعبير الذي لا حد كبير ما طلبت:

/
   \G                     # start where the last match left off
   (?>                    # begin non-backtracking expression
       .*?                # *anything* until...
       <[Aa]\b            # an anchor tag
    )??                   # but look ahead to see that the rest of the expression
                          #    does not match.
    \s+                   # at least one space
    ( \p{Alpha}           # Our first capture, starting with one alpha
      \p{Alnum}*          # followed by any number of alphanumeric characters
    )                     # end capture #1
    (?: \s* = \s*         # a group starting with a '=', possibly surrounded by spaces.
        (?: (['"])        # capture a single quote character
            (.*?)         # anything else
             \2           # which ever quote character we captured before
        |   ( [^>\s'"]+ ) # any number of non-( '>', space, quote ) chars
        )                 # end group
     )?                   # attribute value was optional
/msx;

"ولكن الانتظار" قد يقول."ماذا عن *تعليقات?!?!" حسنا, إذا كنت يمكن أن تحل محل . في عدم التراجع القسم:(كما يعالج CDATA أقسام.)

(?:[^<]|<[^!]|<![^-\[]|<!\[(?!CDATA)|<!\[CDATA\[.*?\]\]>|<!--(?:[^-]|-[^-])*-->)
  • أيضا إذا أردت تشغيل تبديل تحت بيرل 5.10 (و أعتقد PCRE) ، يمكنك وضع \K قبل اسم السمة وليس لديك ما يدعو للقلق حول الاستيلاء على جميع الأشياء التي كنت ترغب في تخطي.

رمز شعار الرد:يجب أن لا قرص/تعديل/الحصاد/أو تنتج html/xml باستخدام التعبير العادية.

وهناك أيضا ركن القضية الشرطية مثل \' و \" التي يجب أن تكون مسؤولة.كنت أفضل حالا باستخدام السليم DOM محلل محلل XML ، أو واحدة من العديد من غيرها من عشرات مجربة أدوات هذا العمل بدلا من اختراع الخاصة بك.

لا يهمني حقا أي واحد يمكنك استخدام ، طالما معترف بها, اختبار, استخدام واحد.

my $foo  = Someclass->parse( $xmlstring ); 
my @links = $foo->getChildrenByTagName("a"); 
my @srcs = map { $_->getAttribute("src") } @links; 
# @srcs now contains an array of src attributes extracted from the page. 

فقط أن نتفق مع الجميع:لا تحليل HTML باستخدام regexp.

فإنه ليس من الممكن إنشاء تعبير سيتم انتقاء الصفات حتى الصحيح قطعة من HTML ، لا يهم كل ممكن تالف المتغيرات.الخاص بك regexp بالفعل الى حد كبير غير قابلة للقراءة حتى من دون محاولة للتعامل مع غير صالحة عدم الاقتباس ؛ مطاردة الى مزيد من الرعب في العالم الحقيقي HTML و سوف تقود نفسك مجنون مع unmaintainable النقطة لا يمكن الاعتماد عليها عبارات.

هناك المكتبات الموجودة إما قراءة كسر HTML أو الصحيح في صالحة XHTML والتي يمكنك ثم تلتهم مع محلل XML.استخدام لهم.

لا يمكنك استخدام نفس اسم لعدة يلتقط.وبالتالي لا يمكنك استخدام الكمية على التعبير مع اسمه يلتقط.

لذا إما أن لا تستخدم اسمه يلتقط:

(?:(\b\w+\b)\s*=\s*("[^"]*"|'[^']*'|[^"'<>\s]+)\s+)+

أو لا تستخدم الكمية على هذا التعبير:

(?<name>\b\w+\b)\s*=\s*(?<value>"[^"]*"|'[^']*'|[^"'<>\s]+)

هذا لا تسمح أيضا سمة من القيم ، bar=' baz='quux:

foo="bar=' baz='quux"

حسنا العيب يكون لديك لتجريد البائعين الرائدة زائدة ونقلت بعد ذلك.

PHP (PCRE) و الثعبان

بسيطة السمة استخراج (ترى العمل):

((?:(?!\s|=).)*)\s*?=\s*?["']?((?:(?<=")(?:(?<=\\)"|[^"])*|(?<=')(?:(?<=\\)'|[^'])*)|(?:(?!"|')(?:(?!\/>|>|\s).)+))

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

(?:\<\!\-\-(?:(?!\-\-\>)\r\n?|\n|.)*?-\-\>)|(?:<(\S+)\s+(?=.*>)|(?<=[=\s])\G)(?:((?:(?!\s|=).)*)\s*?=\s*?[\"']?((?:(?<=\")(?:(?<=\\)\"|[^\"])*|(?<=')(?:(?<=\\)'|[^'])*)|(?:(?!\"|')(?:(?!\/>|>|\s).)+))[\"']?\s*)

(يعمل بشكل أفضل مع "gisx" الأعلام.)


جافا سكريبت

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

(\S+)=[\'"]?((?:(?!\/>|>|"|\'|\s).)+)

splattne,

@VonC الحل جزئيا يعمل ولكن هناك بعض المسألة إذا كان العلامة مختلطة من المسعرة و نقلت

هذا واحد يعمل مع مختلطة سمات

$pat_attributes = "(\S+)=(\"|'| |)(.*)(\"|'| |>)"

لاختبار بها

<?php
$pat_attributes = "(\S+)=(\"|'| |)(.*)(\"|'| |>)"

$code = '    <IMG title=09.jpg alt=09.jpg src="http://example.com.jpg?v=185579" border=0 mce_src="example.com.jpg?v=185579"
    ';

preg_match_all( "@$pat_attributes@isU", $code, $ms);
var_dump( $ms );

$code = '
<a href=test.html class=xyz>
<a href="test.html" class="xyz">
<a href=\'test.html\' class="xyz">
<img src="http://"/>      ';

preg_match_all( "@$pat_attributes@isU", $code, $ms);

var_dump( $ms );

$ms عندئذ تحتوي على مفاتيح وقيم في 2 و 3 عنصر.

$keys = $ms[1];
$values = $ms[2];

هذا هو بلدي أفضل التعابير المنطقية لاستخراج الخصائص في علامة HTML:

# تقليم المباراة داخل الاقتباس (مفردة أو مزدوجة)

(\S+)\s*=\s*([']|["])\s*([\W\w]*?)\s*\2

# بدون تقليم

(\S+)\s*=\s*([']|["])([\W\w]*?)\2

الايجابيات:

  • كنت قادرا على تقليم المحتوى داخل الاقتباس.
  • مباراة كل أحرف ASCII داخل الاقتباس.
  • إذا كان لديك عنوان="أنت لي" ، RegEx لا كسر

سلبيات:

  • تقوم بإرجاع 3 مجموعات ؛ أول مكان الإقامة ثم الاقتباس ("|') و في نهاية الملكية داخل ونقلت أي: <div title="You're"> والنتيجة هي مجموعة 1:عنوان المجموعة 2:"المجموعة 3:أنت.

هذا هو على الانترنت RegEx سبيل المثال:https://regex101.com/r/aVz4uG/13



أنا عادة استخدام هذه التعابير المنطقية لاستخراج HTML Tags:

أوصي هذا إذا كنت لا تستخدم الوسم نوع مثل <div, <span, ، وما إلى ذلك.

<[^/]+?(?:\".*?\"|'.*?'|.*?)*?>

على سبيل المثال:

<div title="a>b=c<d" data-type='a>b=c<d'>Hello</div>
<span style="color: >=<red">Nothing</span>
# Returns 
# <div title="a>b=c<d" data-type='a>b=c<d'>
# <span style="color: >=<red">

هذا هو على الانترنت RegEx سبيل المثال:https://regex101.com/r/aVz4uG/15

الخلل في هذه التعابير المنطقية هي:

<div[^/]+?(?:\".*?\"|'.*?'|.*?)*?>

في هذا الوسم:

<article title="a>b=c<d" data-type='a>b=c<div '>Hello</article>

يعود <div '> ولكن يجب أن لا عودة أي مباراة:

Match:  <div '>

إلى "حل" هذا إزالة [^/]+? نمط:

<div(?:\".*?\"|'.*?'|.*?)*?>


الجواب #317081 هو جيد لكنه لا تتطابق بشكل صحيح مع هذه الحالات:

<div id="a"> # It returns "a instead of a
<div style=""> # It doesn't match instead of return only an empty property
<div title = "c"> # It not recognize the space between the equal (=)

هذا هو التحسين:

(\S+)\s*=\s*["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))?[^"']*)["']?

مقابل

(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?

تجنب المسافات بين إشارة المساواة:(\S+)\s*=\s*((?:...

تغيير الماضي + و .ل:|[>"']))?[^"']*)["']?

هذا هو على الانترنت RegEx سبيل المثال:https://regex101.com/r/aVz4uG/8

شيء مثل هذا قد يكون من المفيد

'(\S+)\s*?=\s*([\'"])(.*?|)\2

أقترح عليك أن تستخدم HTML مرتبة تحويل HTML الى XHTML, ومن ثم استخدام مناسبة تعبير XPath لاستخراج سمات.

إذا كنت تريد أن تكون عامة ، يجب أن ننظر إلى مواصفات دقيقة من علامة ، مثل هنا.ولكن حتى مع ذلك ، إذا كان لديك الخاص بك الكمال regexp ما إذا كان لديك تالف html ؟

وأود أن أقترح عليك أن تذهب لمكتبة تحليل html, اعتمادا على اللغة التي تعمل مع:على سبيل المثالمثل بايثون شوربة جميلة.

إذا كنت في .صافي أوصي HTML agility pack, قوي جدا حتى مع تالف HTML.

ثم يمكنك استخدام XPath.

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

العلامات والصفات HTML يكون على شكل

<tag 
   attrnovalue 
   attrnoquote=bli 
   attrdoublequote="blah 'blah'"
   attrsinglequote='bloob "bloob"' >

لتتناسب مع السمات تحتاج regex attr أن يجد واحدة من أربعة أشكال.ثم كنت بحاجة للتأكد من أن فقط مباريات ذكرت في علامات HTML.على افتراض لديك الصحيحة باستخدام التعابير المنطقية ، المجموع regex ليكون:

attr(?=(attr)*\s*/?\s*>)

Lookahead يضمن أن فقط سمات أخرى وإغلاق الوسم اتبع السمة.انا استخدم العادي التالي التعبير attr:

\s+(\w+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^><"'\s]+)))?

غير مهم المجموعات مصنوعة عدم التقاط.أول مطابقة مجموعة $1 يعطيك اسم السمة قيمة أحد $2أو $3 أو $4.يمكنني استخدام $2$3$4 إلى استخراج قيمة.النهائي هو regex

\s+(\w+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^><"'\s]+)))?(?=(?:\s+\w+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^><"'\s]+))?)*\s*/?\s*>)

ملاحظة:أنا إزالة جميع لا لزوم لها المجموعات في lookahead وجعل كل المجموعات المتبقية عدم التقاط.

أنا أيضا بحاجة إلى هذا وكتب وظيفة تحليل سمات يمكنك الحصول عليه من هنا:

https://gist.github.com/4153580

(ملاحظة:لا يستخدم regex)

لقد خلق وظيفة PHP يمكن أن استخراج سمات أي علامات HTML.فإنه يمكن أيضا التعامل مع سمات مثل disabled هذا لا قيمة له, و أيضا يمكنك تحديد ما إذا كانت العلامة هي بذاتها الوسم (لا إغلاق الوسم) أو لا (يجب إغلاق الوسم) عن طريق التحقق content النتيجة:

/*! Based on <https://github.com/mecha-cms/cms/blob/master/system/kernel/converter.php> */
function extract_html_attributes($input) {
    if( ! preg_match('#^(<)([a-z0-9\-._:]+)((\s)+(.*?))?((>)([\s\S]*?)((<)\/\2(>))|(\s)*\/?(>))$#im', $input, $matches)) return false;
    $matches[5] = preg_replace('#(^|(\s)+)([a-z0-9\-]+)(=)(")(")#i', '$1$2$3$4$5<attr:value>$6', $matches[5]);
    $results = array(
        'element' => $matches[2],
        'attributes' => null,
        'content' => isset($matches[8]) && $matches[9] == '</' . $matches[2] . '>' ? $matches[8] : null
    );
    if(preg_match_all('#([a-z0-9\-]+)((=)(")(.*?)("))?(?:(\s)|$)#i', $matches[5], $attrs)) {
        $results['attributes'] = array();
        foreach($attrs[1] as $i => $attr) {
            $results['attributes'][$attr] = isset($attrs[5][$i]) && ! empty($attrs[5][$i]) ? ($attrs[5][$i] != '<attr:value>' ? $attrs[5][$i] : "") : $attr;
        }
    }
    return $results;
}

اختبار التعليمات البرمجية

$test = array(
    '<div class="foo" id="bar" data-test="1000">',
    '<div>',
    '<div class="foo" id="bar" data-test="1000">test content</div>',
    '<div>test content</div>',
    '<div>test content</span>',
    '<div>test content',
    '<div></div>',
    '<div class="foo" id="bar" data-test="1000"/>',
    '<div class="foo" id="bar" data-test="1000" />',
    '< div  class="foo"     id="bar"   data-test="1000"       />',
    '<div class id data-test>',
    '<id="foo" data-test="1000">',
    '<id data-test>',
    '<select name="foo" id="bar" empty-value-test="" selected disabled><option value="1">Option 1</option></select>'
);

foreach($test as $t) {
    var_dump($t, extract_html_attributes($t));
    echo '<hr>';
}

هذا يعمل بالنسبة لي.كما تأخذ في الاعتبار بعض نهاية الحالات التي صادفتها.

أنا باستخدام هذا Regex عن محلل XML

(?<=\s)[^><:\s]*=*(?=[>,\s])

استخراج العنصر:

var buttonMatcherRegExp=/<a[\s\S]*?>[\s\S]*?<\/a>/;
htmlStr=string.match( buttonMatcherRegExp )[0]

ثم استخدام مسج تحليل واستخراج بت تريد:

$(htmlStr).attr('style') 

إلقاء نظرة على هذا Regex & PHP - عزل سمة src من الوسم img

ربما يمكنك المشي من خلال دوم والحصول على المطلوب من الصفات.أنه يعمل بشكل جيد بالنسبة لي الحصول على سمات من الجسم-الوسم

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