使用正则表达式匹配两个字符串之间的字符串,同时排除字符串

时间:2010-01-02 22:53:12

标签: regex regex-negation

继续我提出的previous question

  

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

我得到了这个答案:

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

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

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

  

外部开始一些文字内部开始 文字 - 我想要 内端一些更多文字外端

我希望“某些文字”和“更多文字”不包含“不需要的”这个词。

换句话说,这没关系:

  

外部开始某些想要的文字内部开始 我想要的文字 内端一些更想要的文字外端

但这不行:

  

外部开始一些不需要的文字内部开始 我想要的文字 内端一些更多不需要的文字外端

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

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

6 个答案:

答案 0 :(得分:5)

.*?替换第一个和最后一个(但不是中间的)(?:(?!unwanted).)*?。 (其中(?:...)是非捕获组,而(?!...)是否定前瞻。)

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

答案 1 :(得分:2)

问自己的一个更好的问题是“我如何使用正则表达式执行此操作?”是“我该如何解决这个问题?”。换句话说,不要试图解决正则表达式的大问题。如果你能解决正则表达式的一半问题,那么就这样做,然后用另一个正则表达式或其他技术解决另一半问题。

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

答案 2 :(得分:1)

您可以将.*?替换为

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

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

答案 3 :(得分:1)

使用普通正则表达式无法轻松实现这一点,但是像Perl这样的某些系统具有使其更容易的扩展。一种方法是使用负向前瞻断言:

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

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

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

答案 4 :(得分:0)

尝试更换最后一个。*?用:(?!(。*不需要的文字。*))

有效吗?

答案 5 :(得分:0)

托拉,重新提出这个问题,因为它有一个相当简单的正则表达式解决方案,没有提到。此问题是此问题中解释为"regex-match a pattern, excluding..."

的技术的典型案例

我们的想法是建立一个替代(一系列|),其中左侧匹配我们不想要的,以便将其排除在外...然后|的最后一侧与我们想要的匹配,并将其捕获到组1.如果设置了组1,则检索它并且您有匹配。

那么我们不想要什么?

首先,如果unwantedouter-start之间存在inner-start,我们希望消除整个外部区块。你可以用:

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

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

其次,如果unwantedinner-end之间存在outer-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

this demo上,查看右侧的第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)

See demo:它直接匹配您想要的内容。

在下面的问题和文章中详细解释了该技术。

参考