12

我有以下字符串:

Lorem ipsum Test dolor sit amet, consetetur sadipscing elitr, sed diam nonumy <a href="http://Test.com/url">Test</a> eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd sed Test dolores et ea rebum. Stet clita kasd gubergren, no sea <a href="http://url.com">Test xyz</a> takimata sanctus est Lorem ipsum dolor sit amet.

现在我将替​​换标签之外的字符串“Test”而不是标签之间的字符串(例如替换为“1234”)。

Lorem ipsum 1234 dolor sit amet, consetetur sadipscing elitr, sed diam nonumy <a href="http://Test.com/url">Test</a> eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd sed 1234 dolores et ea rebum. Stet clita kasd gubergren, no sea <a href="http://url.com">Test xyz</a> takimata sanctus est Lorem ipsum dolor sit amet.

我从这个正则表达式开始:(?!<a[^>]*>)(Test)([^<])(?!</a>)

但是有两个问题没有解决:

  1. 标签内的文本“测试”也被替换(例如<a href="http://Test.com/url">
  2. 标签之间的文本是否与搜索的文本不完全匹配,它也会被替换(例如<a href="http://url">Test xyz</a>

我希望有人有解决这个问题的方法。

4

5 回答 5

20

回答

采用

(Test)(?!(.(?!<a))*</a>)

解释

让我提醒您一些符号的含义:

1)?!是一个否定的前瞻,例如r(?!d)选择所有r不直接跟在后面的d

在此处输入图像描述

2)因此,永远不要在没有字符的情况下开始负前瞻。只是(?!d)没有意义:

在此处输入图像描述

3)?可以用作惰性匹配。例如.+E将从中选择

123EEE

整个字符串123EEE。但是,根据需要.+?E选择尽可能少的“任何字符”( .+)。它只会选择123E.

回答:

Protist 的答案是你应该使用(?!<a[^>]*?>)(Test)(?![^<]*?</a>). 让我先解释一下如何缩短它。

如 2) 所述,在比赛前进行前瞻是没有意义的。所以以下等价于原生答案:

(Test)(?![^<]*?</a>)

也既然<不允许,懒惰的匹配?是多余的,所以它也相当于

(Test)(?![^<]*</a>)

这将选择所有Test后面</a>没有的,中间没有符号<。这就是为什么出现在 any 之前或之后的 Test<a ...> .. </a>将被替换。

但是,请注意

Lorem Test dolor <a href="http://Test.com/url">Test <strong>dolor</strong></a> eirmod

将更改为

Lorem 1234 dolor <a href="http://1234.com/url">1234 <strong>dolor</strong></a> eirmod 

为了抓住这一点,您可以将您的正则表达式更改为

(Test)(?!(.(?!<a))*</a>)

它执行以下操作:

Test选择后面不跟字符串的每个单词,***</a>其中每个字符***后面不跟<a.

请注意,点.很重要(见 2))。

请注意,惰性匹配 like(Test)(?!(.(?!<a))*?</a>)是不相关的,因为嵌套链接在 HTML4 和 HTML5 中是非法的(smth like <a href="#">..<a href="#">...</a>..</a>).

原生生物说

此外,不建议在原始 HTML 上使用正则表达式。

我同意这一点。一个问题是,如果标签没有关闭或打开,就会导致问题。例如,这里提到的所有解决方案都会改变

Lorem Test dolor Test <strong>dolor</strong></a> eirmod

Lorem Test dolor Test <strong>dolor</strong></a> eirmod 1234 dolores sea 1234 takimata 
于 2017-10-25T16:38:04.393 回答
12
(?!<a[^>]*?>)(Test)(?![^<]*?</a>)

与 zb226 相同,但使用惰性匹配进行了优化

此外,不建议在原始 HTML 上使用正则表达式。

于 2012-09-19T11:48:17.860 回答
4

这应该可以解决问题:

(?!<a[^>]*>)(Test)(?![^<]*</a>)

在 regexr 上自己尝试一下。

后续:正如亚当上面解释的那样,第一部分没有效果,可以完全删除:

(Test)(?![^<]*</a>)
于 2012-09-19T11:24:03.863 回答
3

复活这个古老的问题,因为它有一个没有提到的简单解决方案。

关于使用正则表达式解析 html 的所有免责声明,这里有一个简单的方法。

Perl / PCRE 的方法

<a[^>]*>[^<]*<\/a(*SKIP)(*F)|Test

演示

通用解决方案

<a[^>]*>[^<]*<\/a|(Test)

在这个版本中,要替换的文本被捕获在第 1 组中,并通过简单的回调或 lambda 执行替换。

演示

参考

  1. 除了情况 s1、s2、s3 之外,如何匹配模式
  2. 有关代码实现,请参阅如何匹配模式中的代码示例,除非...
于 2014-05-15T00:06:36.343 回答
0

通过@protist 调整建议的解决方案,在这种情况下搜索短语并排除脚本标记内的任何匹配项:

(?!<script[^>]*?>)(\bTest Phrase\b)(?![^<]*?<\/script>)

演示

Adam 提供的答案虽然更简洁,但执行起来需要更长的时间。这可以通过编辑此评论中已经提到的演示来证明。

于 2019-06-05T16:46:18.017 回答