我知道可以匹配一个单词,然后用其他工具逆转比赛(例如 grep -v)。但是,可以匹配不包含一个特定的单词,例如 hede,使用常规表达式的线条吗?

入口:

hoho
hihi
haha
hede

代码:

grep "<Regex for 'doesn't contain hede'>" input

所需的产量:

hoho
hihi
haha

当前回答

有了负面看法,正常的表达可以匹配一些不包含特定的模式的东西,这是由Bart Kiers回答和解释的。

但是,与Bart Kiers的答案, lookahead 部分将测试 1 到 4 个字符在前面,同时匹配任何一个字符. 我们可以避免这一点,让 lookahead 部分检查整个文本,确保没有“hede”,然后正常部分(*)可以同时吃整个文本。

下面是改进的雷格斯:

/^(?!.*?hede).*$/

请注意,在负面 lookahead 部分的 (*?) lazy 量子是可选的,您可以根据您的数据使用 (*) greedy 量子:如果“hede”是存在的,在文本的初半, lazy 量子可以更快;否则, greedy 量子会更快。

这里是Demo代码。

此外,请查看RegexGen.js,一个JavaScript常规表达式发明器,有助于构建复杂的常规表达式。

var _ = regexGen;

var regex = _(
    _.startOfLine(),             
    _.anything().notContains(       // match anything that not contains:
        _.anything().lazy(), 'hede' //   zero or more chars that followed by 'hede',
                                    //   i.e., anything contains 'hede'
    ), 
    _.endOfLine()
);

其他回答

TXR 语言支持 regex 拒绝。

$ txr -c '@(repeat)
@{nothede /~hede/}
@(do (put-line nothede))
@(end)'  Input

一个更复杂的例子:匹配所有从 a 开始和 z 结束的线条,但不包含底层的线条:

$ txr -c '@(repeat)
@{nothede /a.*z&~.*hede.*/}
@(do (put-line nothede))
@(end)' -
az         <- echoed
az
abcz       <- echoed
abcz
abhederz   <- not echoed; contains hede
ahedez     <- not echoed; contains hede
ace        <- not echoed; does not end in z
ahedz      <- echoed
ahedz

雷格克斯的拒绝本身并不特别有用,但当你也有交叉时,事情变得有趣,因为你有一个完整的布莱恩组操作:你可以表达“与此相匹配的组,除了与此相匹配的东西”。

基准

我决定评估一些提交的选项,并比较其性能,以及使用一些新功能。

参考文本:

第一 7 行不应匹配,因为它们包含所搜索的表达式,而下 7 行应匹配!

Regex Hero is a real-time online Silverlight Regular Expression Tester.
XRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero
egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester.
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester.

Regex Her
egex Hero
egex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester.
Nobody is a real-time online Silverlight Regular Expression Tester.
Regex Her o egex Hero Regex  Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.

结果:

结果是每秒以 3 轮的平均值 - 大数 = 更好

01: ^((?!Regex Hero).)*$                    3.914   // Accepted Answer
02: ^(?:(?!Regex Hero).)*$                  5.034   // With Non-Capturing group
03: ^(?!.*?Regex Hero).*                   7.356   // Lookahead at the beginning, if not found match everything
04: ^(?>[^R]+|R(?!egex Hero))*$             6.137   // Lookahead only on the right first letter
05: ^(?>(?:.*?Regex Hero)?)^.*$             7.426   // Match the word and check if you're still at linestart
06: ^(?(?=.*?Regex Hero)(?#fail)|.*)$       7.371   // Logic Branch: Find Regex Hero? match nothing, else anything

P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT))  ?????   // Logic Branch in Perl - Quick FAIL
P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ?????   // Direct COMMIT & FAIL in Perl

由于.NET 不支持操作 Verbs (*FAIL 等) 我无法测试 P1 和 P2 解决方案。

总结:

总的来说,最可读和最快的解决方案似乎是03与一个简单的负面视图,这也是JavaScript的最快的解决方案,因为JS不支持其他解决方案的更先进的Regex功能。

^((?!hede).)*$

而且,如果你需要匹配线打破车也,使用DOT-ALL修改器(在下面的模式中的跟踪器):

/^((?!hede).)*$/s

或使用 inline:

/(?s)^((?!hede).)*$/

如果 DOT-ALL 修改器不适用,您可以模拟相同的行为与字符类 [\s\S]:

/^((?!hede)[\s\S])*$/

解释

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│
    └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘
    
index    0      1      2      3      4      5      6      7

在哪里是e的是空的线条. 雷格斯(?!hede)看向前看,看看是否没有任何字符的“hede”可以看到,如果是这样的情况(所以另一个东西可以看到),那么.(dot)将匹配任何字符,除了线条中断。

正如你可以看到的,输入“ABhedeCD”将失败,因为在e3上, regex(?!hede)失败(有“hede”在前面!)。

更简单的解决方案是使用非运营商!

如果您的声明需要匹配“内容”而不匹配“排除”。

var contains = /abc/;
var excludes =/hede/;

if(string.match(contains) && !(string.match(excludes))){  //proceed...

我相信RegEx的设计师预测了非运营商的使用。

我想添加另一个例子,如果你试图匹配一个包含X线的整个线,但也不包含Y线。

这个 regex 模式会工作(在 JavaScript 中也工作)

^(?=.*?tasty-treats)((?!chocolate).)*$

(全球,多线旗在例子中)

互动示例: https://regexr.com/53gv4

比赛

(这些 URL 包含“蛋糕治疗”并且不包含“巧克力”)

example.com/tasty-treats/strawberry-ice-cream example.com/甜点/tasty-treats/banana-pudding example.com/tasty-treats-overview

没有匹配

example.com/tasty-treats/chocolate-cake example.com/home-cooking/over-roasted-chicken example.com/tasty-treats/banana-chocolate-fudge example.com/desserts/chocolate/tasty-treats example.com/chocolate/tasty-treats/desserts