5

继我提出的上一个问题之后:

如何使用正则表达式匹配两个字符串之间的文本,其中这两个字符串本身包含两个其他字符串,并且内部和外部封闭字符串之间有任意数量的文本?

我得到了这个答案:

/outer-start.*?inner-start(.*?)inner-end.*?outer-end/

我现在想知道如何从外部封闭字符串和内部封闭字符串之间的文本中排除某些字符串。

例如,如果我有这个文本:

外部开始一些文本内部开始 文本我想要的 内部结束一些更多文本外部结束

我希望“一些文本”和“更多文本”不包含“不需要”这个词。

换句话说,这没关系:

外部开始一些想要的文本内部开始 文本我想要的 内部结束一些更想要的文本外部结束

但这不行:

外部开始一些不需要的文本内部开始 文本我想要的 内部结束一些更多不需要的文本外部结束

或者进一步解释,上面前面的答案中外部和内部分隔符之间的表达应该排除“不需要”这个词。

这很容易使用正则表达式匹配吗?

4

6 回答 6

6

将第一个和最后一个(但不是中间).*?替换为(?:(?!unwanted).)*?. (where(?:...)是非捕获组,并且(?!...)是负前瞻。)

但是,这很快就会在任何实际(而不是示例)使用中出现极端情况和警告,如果您要询问您真正在做什么(使用真实示例,即使它们被简化,而不是虚构示例),您可能会得到更好的答案。

于 2010-01-02T23:03:25.783 回答
2

问自己一个比“我如何使用正则表达式做到这一点?”更好的问题。是“我该如何解决这个问题?”。换句话说,不要沉迷于尝试用正则表达式解决一个大问题。如果你可以用正则表达式解决一半的问题,那么就这样做,然后用另一个正则表达式或其他技术解决另一半。

例如,传递您的数据以获取所有匹配项,忽略不需要的文本(阅读:获取包含和不包含不需要的文本的结果)。然后,对减少的数据集进行传递,并清除那些包含不需要文本的结果。这种解决方案更容易编写、更容易理解并且随着时间的推移更容易维护。对于您可能需要用这种方法解决的任何问题,它都足够快。

于 2010-01-02T23:33:40.230 回答
1

您可以替换.*?

 ([^u]|u[^n]|un[^w]|unw[^a]|unwa[^n]|unwan[^t]|unwant[^e]|unwante[^d])*?

这是“纯”正则表达式的解决方案;您使用的语言可能允许您使用一些更优雅的结构。

于 2010-01-02T23:02:02.463 回答
1

你不能用普通的正则表达式轻松地做到这一点,但某些系统(如 Perl)具有使其更容易的扩展。一种方法是使用否定的前瞻断言:

/outer-start(?:u(?!nwanted)|[^u])*?inner-start(.*?)inner-end.*?outer-end/

关键是将“不想要的”分成(“u”后面没有“nwanted”)或(不是“u”)。这允许模式前进,但仍会找到并拒绝所有“不需要的”字符串。

如果你做了很多这样的事情,人们可能会开始讨厌你的代码。;)

于 2010-01-02T23:05:52.573 回答
0

Tola,复活了这个问题,因为它有一个相当简单的正则表达式解决方案,但没有提到。这个问题是这个问题中解释的“正则表达式匹配模式,不包括......”的技术的经典案例

这个想法是建立一个交替(一系列|),其中左侧匹配我们不想要的东西,以便让它不碍事......然后匹配我们想要的|东西,并捕获它到第 1 组。如果设置了第 1 组,您检索它并且您有一个匹配项。

那么我们不想要什么?

首先,如果和unwanted之间存在,我们要消除整个外部块。你可以这样做:outer-startinner-start

outer-start(?:(?!inner-start).)*?unwanted.*?outer-end

这将在第一个的左侧|。它匹配整个外部块。

其次,如果和unwanted之间存在,我们要消除整个外部块。你可以这样做:inner-endouter-end

outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end

这将是中间|。它看起来有点复杂,因为我们要确保“懒惰”*?不会跳过块的末尾进入不同的块。

第三,我们匹配并捕获我们想要的东西。这是:

inner-start\s*(text-that-i-want)\s*inner-end

因此,在自由间距模式下,整个正则表达式是:

(?xs)
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this
| # OR (also don't want that)
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end
| # OR capture what we want
inner-start\s*(text-that-i-want)\s*inner-end

此演示中,查看右侧的第 1 组捕获:它包含我们想要的内容,并且仅适用于正确的块。

在 Perl 和 PCRE(例如在 PHP 中使用)中,您甚至不必查看第 1 组:您可以强制正则表达式跳过我们不想要的两个块。正则表达式变为:

(?xs)
(?: # non-capture group: the things we don't want
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this
| # OR (also don't want that)
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end
)
(*SKIP)(*F) # we don't want this, so fail and skip
| # OR capture what we want
inner-start\s*\Ktext-that-i-want(?=\s*inner-end)

见演示:它直接匹配你想要的。

该技术在下面的问题和文章中进行了详细说明。

参考

于 2014-06-25T23:30:55.700 回答
-1

尝试替换最后一个 .*? 与:(?!(。*不需要的文本。*))

它奏效了吗?

于 2010-01-02T23:01:35.900 回答