正则表达式"替换直到"

时间:2017-01-16 14:06:57

标签: regex

这比similar questions更复杂(对我来说!)。

我尝试将某些日期与一些旧HTML中的Regex复制到另一个位置,但是当我重复搜索并替换时,在所需块之外扩展的替换有问题。

在下面的示例中,每个块< ul> ..< / ul>表示第一个< li> ..< b>中包含的特定日期。我要复制" 2005年10月13日"进入随后的< li> ..< b>,同样地," 2005年10月14日"进入随后的< li> ..< b>也是,但不在其之外< ul> ..< / ul>块。

我可以使用以下正则表达式(由Funduc的Windows搜索和替换实用程序使用,显然是#34; UNIX grep表示法的一个子集)":

Search: <li>+[0-9] *<b>*[]<li><b>
Replace: <li>%1 %2\<b>%3\<li>%1 %2\<b>

+ [0-9]是一个或多个数字; *是按字母顺序排列的; * []是任何东西; %1 ..%4是替换位置。

这是我的原始HTML

<ul>
<li>13 Oct 2005<b>Title One</b>
Some text
<p>
<li><b>Title Two</b>
Some more text
<p>

</ul>

<ul>
<li>14 Oct 2005<b>Title 3</b>
Another line of text
<p>
<li><b>Title 4</b>
Yet another line of text
<p>
<li><b>Title 5</b>
Some text
<p>

</ul>

在我的第一个脚本运行后,这正确地给了我:

<ul>
<li>13 Oct 2005<b>Title One</b>
Some text
<p>
<li>13 Oct 2005<b>Title Two</b>
Some more text
<p>

</ul>

<ul>
<li>14 Oct 2005<b>Title 3</b>
Another line of text
<p>
<li>14 Oct 2005<b>Title 4</b>
Yet another line of text
<p>
<li><b>Title 5</b>
Some text
<p>

</ul>

但在我的第二个脚本运行后,2005年10月13日被错误地添加到下一个&lt; ul&gt; ..&lt; ul&gt;块:

<ul>
<li>13 Oct 2005<b>Title One</b>
Some text
<p>
<li>13 Oct 2005<b>Title Two</b>
Some more text
<p>

</ul>

<ul>
<li>14 Oct 2005<b>Title 3</b>
Another line of text
<p>
<li>14 Oct 2005<b>Title 4</b>
Yet another line of text
<p>
<li>13 Oct 2005<b>Title 5</b>    <-- wrong !!!
Some text
<p>

</ul>

我有大约20,000个&lt; ul&gt; ..&lt; ul&gt;块(因此脚本),并且每个块包含1-10&lt; li&gt;&lt; b&gt;之间的块。带标题的标签。我以为它不可能一次完成。

1 个答案:

答案 0 :(得分:0)

tl; dr正则表达式是错误的工具;用更强的东西。

请不要

使用正则表达式解析HTML是bad idea。它甚至在SO正则表达式引用中:Reference - What does this regex mean?

所以不要这样做。

是的,我看到你还在这里

如果你完全负责你的HTML文件,并且你不想要通用工具或任何东西,我不能阻止你使用正则表达式。

仍然没有

正如您所注意到的,单个正则表达式是错误的工具。至关重要的是,正则表达式,即使是具有反向引用和前瞻功能的强大表达式,也没有额外记忆他们看的内容。

但这正是你在这里所要求的!您想知道您是否已离开<ul>块,同时仅查看用于界定您要搜索的内容的日期和标记。

您需要的是一种编程语言。

样式点

您使用的正则表达式语法与unix样式的正则表达式语法完全不同。这是可以原谅的。

对于任何正则表达式爱好者而言,不可原谅的是使用多行正则表达式而不解释为什么必要。

啊哈!可是等等!现在我们已经得出结论,我们需要一种编程语言,不再需要多行正则表达式!

所以,让我们停止使用它们。

为什么我们还在这里?

此时,我在这里是为了自我鞭挞:我得出结论,一方面,我们需要一种编程语言,因为我们需要比正则表达更强的东西;另一方面,我不会使用HTML解析器,因为我发誓我只使用正则表达式。

我显然是个白痴,你不应该听我说的任何话。

反常解决方案

一旦我们允许自己使用编程语言,我们就可以一次性修复文件。我们只需要保存一个小状态:当前<ul>块中的日期。

这是一个符合我为自己设定的可怕目标的Perl脚本(我使用的是5.22):

#! /usr/bin/perl

use strict;
use warnings;

my $date_re = qr/^<li>(\d+ [[:alpha:]]+ \d+)<b>/;
my $non_date_title_re = qr/^<li>(<b>.*<\/b>)$/;
my $local_date = '';

while (<>) {
    if (/<\/ul>/) {
        $local_date = '';
    } elsif (/$date_re/) {
        $local_date = $1;
    } elsif (/$non_date_title_re/) {
        s/$non_date_title_re/<li>$local_date$1/;
    }

    print;
}

你可能不会阅读Perl,但这里发生的事情非常清楚:首先,为了清晰起见,在局部变量中保存一些正则表达式:一个用于<li><b>之间的日期,一个用于标题没有约会。

对于文件中的每一行,如果它包含</ul>,则会使我们保存的本地日期无效。 (对于您问题中的文件,此部分并非绝对必要。)如果该行与日期正则表达式匹配,请保存日期以供日后使用。如果该行与非日期图块匹配,请使用替换将我们保存的日期放在<li>之后。

但实际上,请使用HTML解析器。