如何求解贪婪的正则表达式

时间:2019-07-04 10:38:32

标签: php regex regex-lookarounds

我对PHP中的正则表达式有疑问。

应处理此文本:

Start Text1
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
End Text1
Start Text2
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
End Text2

我想在

  • 行中添加

    我尝试使用此模式:

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

    但是给出这样的内容:

    Start Text1
    <ul>
    <li>Item1</li>
    <li>Item2</li>
    <li>Item3</li>
    End Text1
    Start Text2
    <li>Item1</li>
    <li>Item2</li>
    <li>Item3</li>
    </ul>
    End Text2
    

    ...还包括“结束文本1”和“开始文本2”。所以我更喜欢这样的结果:

    Start Text1
    <ul>
    <li>Item1</li>
    <li>Item2</li>
    <li>Item3</li>
    </ul>
    End Text1
    Start Text2
    <ul>
    <li>Item1</li>
    <li>Item2</li>
    <li>Item3</li>
    </ul>
    End Text2
    

    我该怎么做?

    我在这里进行了测试:https://www.phpliveregex.com/p/sHs#tab-preg-replace

  • 1 个答案:

    答案 0 :(得分:2)

    修复正则表达式

    此正则表达式有效:

    (\s*<li>.*?<\/li>\s*)(?!\s*<li>)
    

    说明:

    • .*?要求正则表达式在<li></li>之间尽可能少地匹配,以便一旦<li>中没有文本时它就停止; < / li>
    • 就像您在第一个实例中所做的那样,我在/的第二个实例中逃脱了</li>
    • (?!\s*<li>)说,下一个文本不能是另一个<li>-需要,因为否则,上面的.*?会使它单独匹配每行<li>
    • 最初的(?!<\/li>)实际上没有任何作用,因此我将其删除。

    对换行符进行细化处理

    在Live Regex网站上,我无法在需要的位置插入换行符。

    在php中,您可以使用

    preg_replace('/\s*(<li>.*?<\/li>)\s*(?!\s*<li>)/smi',
       "\n<ul>\n$1\n</ul>\n", $input)
    

    preg_replace('/(\s*<li>.*?<\/li>\s*)(?!\s*<li>)/smi',
       "\n<ul>$1</ul>\n", $input)
    

    以获得更好的结果。关键是将替换模式放在双引号中。

    更好地处理缩进的输入

    如果输入缩进,则您可能还会考虑以下内容:

    preg_replace('(\s*)(<li>.*?<\/li>)(\s*)(?!\s*<li>)/smi',
       "$1<ul>$1$2$1</ul>$3", $input)
    

    这将使<ul></ul>与第一个<li>处于相同的缩进级别,并将周围的文本保留为先前的缩进。

    但是显然,鉴于所有这些间距变体都不会改变结果HTML的解释,所有这些都不是很重要。