【问题标题】:regular expression for checking attributes in an html tag用于检查 html 标记中的属性的正则表达式
【发布时间】:2012-03-26 10:46:34
【问题描述】:

在 HTML 源代码中,我需要提取 FONT 标记内的任何简单文本,其中包含(不多也不少)这 3 个属性,顺序不限:size=5、color="red"、face="verdana" .

因此,例如,正则表达式必须提取除最后四个之外的所有以下“随机文本”。

<font size=5 color="red" face="verdana">randomtext</font>
<font size=5 face="verdana" color="red">randomtext</font>
<font color="red" size=5 face="verdana">randomtext</font>
<font color="red" face="verdana" size=5>randomtext</font>
<font face="verdana" size=5 color="red">randomtext</font>
<font face="verdana" color="red" size=5>randomtext</font>
<font size=5 size=5 size=5>randomtext</font>
<font face="verdana" color="red" size=5 foobar="random">randomtext</font>
<font face="verdana" color="red" size=5 foobar="random=pippo">randomtext</font>
<font face="verdana" color="red" size=5 garbagetext>randomtext</font>

我通过使用 3 个前瞻解决了“按任意顺序”问题:

<font(?=[^>]* size=5)(?=[^>]* color="red")(?=[^>]* face="verdana")[^>]*>([^<]+)</font>

...或者更多的 html 灵活性:

<\s*font(?=[^>]*\s+size\s*=\s*5)(?=[^>]*\scolor\s*=\s*["']red["'])(?=[^>]*\sface\s*=\s*["']verdana["'])[^>]*>\s*([^<]+?)\s*<\s*/font\s*>

问题是它也匹配最后三个。 如何排除那些匹配? (显然,以一种通用且合理的简短/有效方式,即不使用所有可能的正面组合,也不使用仅适用于我的示例的字面负面表达)

【问题讨论】:

  • 您使用什么语言?使用适当的 HTML 解析库可以更轻松地处理此任务。
  • Michael,它必须在单个正则表达式中解决,与语言无关。正则表达式风格是 PCRE。
  • 我已经找到了一个简短的单正则表达式解决方案,但它重复了所有三个属性一次,使我的示例正则表达式的长度加倍。虽然如果我写下所有可能的组合并不长,但我认为它仍然不是更短/最好的解决方案。

标签: regex


【解决方案1】:

一种方式,也根据谁说正则表达式不是这项工作的工具:

script.pl 的内容(里面有正则表达式并解释):

use warnings;
use strict;

while ( <DATA> ) {
    printf qq[Text matched: %s\t (original string: %s)\n], $1, $& if 
    m/ 
        # At begin of line, '<' character plus optional space.
        \A < \s*
        # Literal 'font' word.
        font
        # Mandatory space.
        \s+
        # Positive look-ahead for string 'size=5'
        (?= .* size \s* = \s* 5 (?:\s+|>) )   
        # Positive look-ahead for string 'face="verdana"'
        (?= .* face \s* = \s* "verdana" (?:\s+|>) )
        # Positive look-ahead for string 'color="red"'
        (?= .* color \s* = \s* "red" (?:\s+|>) )
        # If last three look-ahead succeed, match them.
        (?:size\s*=\s*5\s*|color\s*=\s*"red"\s*|face\s*=\s*"verdana"\s*){3}
        # Literal '>' character.
        >
        # Text between tags.
        ([^>]+)
        # Close tag and match end of string.
        <\/font> \Z
    /x;
}

__DATA__
<font size=5 color="red" face="verdana">randomtext</font>
<font size=5 face="verdana" color="red">randomtext</font>
<font color="red" size=5 face="verdana">randomtext</font>
<font color="red" face="verdana" size=5>randomtext</font>
<font face="verdana" size=5 color="red">randomtext</font>
<font face="verdana" color="red" size=5>randomtext</font>
<font size=5 size=5 size=5>randomtext</font>
<font face="verdana" color="red" size=5 foobar="random">randomtext</font>
<font face="verdana" color="red" size=5 foobar="random=pippo">randomtext</font>
<font face="verdana" color="red" size=5 garbagetext>randomtext</font>

像这样运行它:

perl script.pl

结果如下:

Text matched: randomtext         (original string: <font size=5 color="red" face="verdana">randomtext</font>)
Text matched: randomtext         (original string: <font size=5 face="verdana" color="red">randomtext</font>)
Text matched: randomtext         (original string: <font color="red" size=5 face="verdana">randomtext</font>)
Text matched: randomtext         (original string: <font color="red" face="verdana" size=5>randomtext</font>)
Text matched: randomtext         (original string: <font face="verdana" size=5 color="red">randomtext</font>)
Text matched: randomtext         (original string: <font face="verdana" color="red" size=5>randomtext</font>)

【讨论】:

  • 伟大的Birei,你到达了我到达的相同解决方案,唯一的“缺陷”是重复3个属性一次。
【解决方案2】:

你意识到这变得越来越困难了吗?如果你还有其他可能,那就用吧!

对于正则表达式,试试这个:

<font(?=[^>]* size=5)(?=[^>]* color="red")(?=[^>]* face="verdana")(?![^>]*(?<!color|size|face)=)(?:\s+[^>\s=]+=[^>\s=]+\s*)+>([^<]+)</font>

here on Regexr

我添加/更改了两件事:

  1. (?![^&gt;]*(?&lt;!color|size|face)=) 是一个负前瞻,在断言后面有一个嵌套的负前瞻,当前面没有颜色、大小或面时,它不允许使用等号。

  2. 我将与属性匹配的[^&gt;]* 更改为(?:\s+[^&gt;\s=]+=[^&gt;\s=]+\s*)+,使其仅匹配不包含等号的非空白序列。

【讨论】:

  • 我认为这个正则表达式也错误地匹配了我的第 7 个和最后一个示例。到目前为止,最好的解决方案是Birei。仍在寻找更紧凑的正则表达式解决方案(两次不包含相同的属性)
  • 您查看过 Regexr 链接吗?它以您想要的方式匹配您的所有示例。
  • 我在 Regexr 中对其进行了测试,发现它也匹配:randomtext。我知道重复属性是没有意义的,但我更喜欢排除匹配项...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多