Perl & Regex:仅当字符串不在 > 和 < 之间时才替换字符串

Perl & Regex: replace string only if it is not between > and <

我想替换><之间的所有字符串,例如,将center(摘自:> is the sun the center of the universe?:<)替换为foo,但不要替换 center(摘自:<...center;">)。

我正在使用以下命令:

perl -pi -w -e 's/center/foo/g;' file.html

所以我尝试使用 replace all "foo" between two HTML tags using REGEX (PHP code),结果是这样的:

perl -pi -w -e 's/(?<![\w$<])$\(center\)(?![\w$>])/foo/g;' file.html

但它不能正常工作我想要的。我在网上搜索了一下,最接近我需要的是 , and 。但是我不能完全解决只替换不是 <center> 的字符串的需要。

fragment_html_code:

</td></tr><tr><th colspan="2" class="" style="text-align:center;">is the sun the center of the universe?:</th></tr><tr class=""><td colspan="2" class="" style="text-align:center;">
center </td></tr>

编辑更新:

关于 Lordadmira 解决方案:

每当 <> 和 <> 之间有一个行跳转时,代码就会失败。例如,当要替换的单词像(这里有一个换行符)center 时失败。它会发生什么?请参阅下面的上下文示例:

</td></tr><tr><th colspan="2" class="" style="text-align:center;">
   (Here there is a line jump and then the solution of Lordadmira fails and does not occur) ----> is the sun the center of the universe?:
    </th></tr><tr class=""><td colspan="2" class="" style="text-align:center;">
        center </td></tr>

编辑更新 01:

我将 Lordadmira 的初始 解决方案修改为 perl -0777 -pi -w -e 's{>\K[^<]*?\K.foo[^<]*(?=<).}{ bar }g;' file.htmlperl -0777 -pi -w -e 's{>\K[^<]*?\K.foo.[^<]*(?=<).}{ bar }g;' file.html,这对换行有效,但它会删除 foo 之后的所有内容。我尝试了几种方法来避免删除 foo 后的文本,但我一直无法获得解决方案。如果万一我设法解决了这个问题,那么这个问题就会得到完整的回答。

编辑更新 02:

我现在已经将我在 EDIT UPDATE 01 中的修改从 Lordadmira 更改为 perl -0777 -pi -w -e 's{>\K[^<]*?\K.foo.[^<](?!=<)}{ bar }g;' 以更正 foo 之后的文本之前被删除的事实。但这是擦除 foo 之后字符串的第一个字符,我想说例如在

> "lorem
  foo ipsum "< 

foo 被替换时,结果不是预期的,因为我得到 >" lorem bar psum "< ,也就是说, ipsum "i" 被删除了.


下面的解决方案解决了每次替换删除 foo 后字符串中有一个字符的问题。目前,在广泛的背景下,这是对 Lordadmira 初始解决方案的最实用的改编。

要解决此问题,需要省略 foo 末尾的运算符点,并在 Regex matching line not containing the string and exhaustively subsidized in the section "Positive and Negative Lookahead" 处添加否定先行作为附加解释, 将 (?=<) 属于 Lordadmira 的初始解决方案 的部分修改为 (?!=<).

perl -0777 -pi -w -e 's{>\K[^<]*?\K.foo[^<](?!=<)}{ bar }g;'


编辑更新 3:

经过几次测试,我相信已经找到了一个最能满足我的意图的解决方案。

perl -0777 -pi -w -e 's{>[^<]*?\K\b(foo)\b(?!=<)}{bar}g;'

你会这样做。

s{>\K[^<]*?center[^<]*(?=<)}{foo}g;

编辑:使用perl -p 命令行逐行读取文件并假定您要执行的所有工作都包含在单行中。如果您需要跨行工作,则必须读入整个文件(或任何足够的块)。使用 perl -0777 -p 它应该可以工作。

有关详细信息,请参阅 perlrun

HTH

我的回答是对上面初始@lordadmira 解决方案的明显改编:

有两件事是促进 Lordadmira 最初解决方案的改编所必需的:使用分界线并在 foo 之后完整保留原始文本。改编如下:

perl -0777 -pi -w -e 's{>\K[^<]*?\K.foo[^<](?!=<)}{ bar }g;'

要解决此问题,需要在 ..\K.foo 的末尾省略 运算符点 ,并在 Regex matching line not containing the string and exhaustively subsidized in the section "Positive and Negative Lookahead" 处添加否定前瞻作为附加解释, 将 (?=<) 属于 Lordadmira 的初始解决方案 的部分修改为 (?!=<).

注意:我不确定它是否适用于所有可能的代码格式或 html 内容上下文,但在我目前所做的测试中已经足够了。

最终解决方案(即在我上面的问题中编辑更新 3):

perl -0777 -pi -w -e 's{>[^<]*?\K\b(foo)\b(?!=<)}{bar}g;'