正则表达式在正则表达式内第一次出现#STRING#时停止

时间:2012-12-12 14:40:17

标签: php regex

*注意:Array()的输出是PHP print_r()*

我有这个HTML标记:

<tr>
    <td width="40" align="left"><div class="icSkill" id="skill4"></div></td>
    <td colspan="2">SOME_VALUE_I_WANT&nbsp;</td>
</tr>

我真的想用RegEx提取它,并且在这种情况下不想使用HTML解析器。

我这样做Regex(我使用s-flag忽略文件的换行符):

\<tr\>\<td\swidth="40"\salign="left"\>\<div\s+class="icSkill"\s+id="skill(\d+)".*\<\/tr\>

现在的问题是正则表达式并没有停留在第一个找到的关闭TR标签,但我想要它。我知道这可能与断言有关,只是我不知道如何。

Array
(
    [0] => <tr><td width="40" align="left"><div class="icSkill" id="skill4"></div></td><td colspan="2">SOME_VALUE_I_WANT&nbsp;
</td></tr><tr><td rowspan="2" align="left"><div class="icGuard" id="guard9"></div></td></tr>
    [1] => 4
)

基本示例如:/ [^&lt;] * /在这种情况下不起作用。还有一种方法可以告诉正则表达式:

/[^A_STRING]*/ (in words; stop unless you find A_STRING)
OR BETTER EXAMPLE:
/[^A_STRING_FIRST_TIME]*/ (in words; stop unless you find A_STRING for the FIRST_TIME)

2 个答案:

答案 0 :(得分:9)

问题是greediness.*消耗尽可能多的消耗。您可以通过附加?

来使其不合适
~<tr><td\s+width="40"\s+align="left"><div\s+class="icSkill"\s+id="skill(\d+)".*?</tr>~s

另外,正如您所看到的,实际上没有必要进行太多的转义。它只会妨碍易读性。

使重复不成熟的另一种方法是使用修饰符U,这使得整个模式中的所有重复都不全面。我更喜欢本地变体(使用?)。

在任何情况下,都有不同的模仿[^A_STRING]*的可能性(它不起作用,因为它匹配任何字符串,不包括A_STRING)。您可以在重复的每个位置使用negative lookahead

(?:(?!A_STRING).)*

(将其替换为.*.*?)。在大多数情况下它应该是等效的,但执行时间可能不同。另外,解密起来有点困难。

答案 1 :(得分:1)

这是一个艰难的。通常你会在那里有一个类标识符,这会使它更容易。

因此,让我们确保理解您的需求:在关闭表格行之前,您需要捕获最后<td>标记内的内容。在这种情况下,您需要一个负向前瞻:

<td(?!.*?<td).*?>(.*?)<\/td>

这与s修饰符一起捕获SOME_VALUE_I_WANT&nbsp;,前提是它位于表格行的最后一个<td>元素中。

这个正则表达式中唯一不直接的元素是负向前瞻操作符<td(?!.*?<td),它只捕获一个<td>元素,后面跟着另一个这样的元素。

此外,当您使用星号运算符时,通常需要确保将其修改为非贪婪,如下所示:(.*?)。这意味着它会在第一场比赛时停止。