2010-01-02 71 views
5

previous question中,我问继:使用正则表达式来匹配两个字符串之间的字符串,而排除串

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

我得到了这样的回答:

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

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

举例来说,如果我有这样的文字:

外启动一些文本内启动文本是 - 我想做内端一些文字外-end

我想'一些文本'和'一些更多的文本'不包含'不想要的'这个词。

换句话说,这是确定:

外启动一些人想要的文字内启动文本是 - 我想做内端一些有用的文字外端

但是,这是不正常:

外启动一些不需要的文本内启动文本是 - 我想做内端一些不需要的文本外端

或进一步解释,上面的回答中的外部分隔符和内部分隔符之间的表达式应排除“不想要的”一词。

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

+0

究竟是你想做些什么? – Gumbo 2010-01-02 23:18:13

回答

5

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

然而,这迅速用极端情况,并警告任何真正的(例如代替)使用结束了,如果你会问什么你真的在做(用真实的例子,即使它们是简化的,而不是示例),你可能会得到更好的答案。

+0

这是比我更好的解决方案。 – 2010-01-02 23:11:34

0

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

它工作?

+1

如果你不确定(即使你认为你确定),你应该在本地(或http://codepad.org/)等网站测试你的模式,这就是为什么正则表达式的问题需要好的例子传球和失败)。 – 2010-01-02 23:21:44

1

您可以

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

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

1

你不能用普通的正则表达式轻松地做到这一点,但是一些系统(比如Perl)具有扩展性,这使得它更容易。一种方法是使用负先行断言:

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

关键是要拆了“不必要的”进(“U”后面没有“nwanted”)或(不是“U”)。这允许模式前进,但仍然会发现并拒绝所有“不需要”的字符串。

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

2

问一问你自己的一个更好的问题,而不是“我如何用正则表达式来做这件事?”是“我该如何解决这个问题?”。换句话说,不要试图用正则表达式来解决一个大问题。如果你可以用正则表达式解决一半的问题,那就这样做,然后用另一个正则表达式或其他技术解决另一半问题。

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

0

托拉,复活这个问题,因为它有一个相当简单的正则表达式的解决方案,没有提到。这个问题是该技术的一个经典案例在这个问题解释"regex-match a pattern, excluding..."

的想法是建立一个交替(一系列|),其中左右两侧比赛我们不是为了得到它想要做然后... |的最后一面与我们想要的匹配,并将其捕获到组1.如果组1被设置,则检索它并且您有匹配。

那么我们不想要什么?

首先,我们想要消除整个外部区块,如果在outer-startinner-start之间有unwanted

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

这将是第一个|左:你可以做到这一点。它匹配整个外部块。

第二,如果在inner-endouter-end之间有unwanted,我们想要消除整个外部块。你可以这样做:

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:它直接匹配你想要什么。

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

参考

相关问题