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

入口:

hoho
hihi
haha
hede

代码:

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

所需的产量:

hoho
hihi
haha

当前回答

也许你会在谷歌上找到这一点,同时试图写一个能够匹配一行(与整个行相反)的分区,这些分区不包含一个字符。

根据字符串: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

我想匹配 <span> 标签,这些标签不包含“坏”字符。

/<span(?:(?!坏)*?>将匹配 <span class=\"good\">和 <span class=\"ugly\">。

请注意,有两组(层)的偏见:

最内在的是对负面观点(这不是捕捉群体) 最外在是由Ruby作为捕捉群体解释的,但我们不希望它成为捕捉群体,所以我补充说:它是开始,它不再被解释为捕捉群体。

在Ruby中展示:

s = '<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>'
s.scan(/<span(?:(?!bad).)*?>/)
# => ["<span class=\"good\">", "<span class=\"ugly\">"]

其他回答

有了负面看法,正常的表达可以匹配一些不包含特定的模式的东西,这是由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()
);

答案非常好,只是一个学术点:

计算机科学的理论意义上的常规表达是不可能这样做的,对他们来说,它应该看起来像这样:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$) 

这只是一场完整的比赛,做下一场比赛会更可怕。

它可能更可维持在您的代码中的两个规则,一个进行第一场比赛,然后如果它匹配运行第二个规则,以检查您想要阻止的其他案例,例如 ^.*(hede)。* 然后在您的代码中有适当的逻辑。

好吧,我承认这不是一个真正的答案发表的问题,它也可能使用一些更多的处理,而不是一个单一的 regex. 但对于开发人员谁来到这里寻找一个快速紧急修复的另一个案例,那么这个解决方案不应该被忽视。

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

原因在于,没有旗帜,POSIX接口只需要使用基本常规表达式(BRE),这些表达式只是不足以完成这个任务,因为缺乏替代的子表达式。

grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" input

(与格雷尔和一些额外的优化手工完成)。

egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" input

#!/bin/bash
REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$"

# First four lines as in OP's testcase.
cat > testinput.txt <<EOF
hoho
hihi
haha
hede

h
he
ah
head
ahead
ahed
aheda
ahede
hhede
hehede
hedhede
hehehehehehedehehe
hedecidedthat
EOF
diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)

Files /dev/fd/63 and /dev/fd/62 are identical

如预期。

对于那些对细节感兴趣的人来说,使用的技术是将与词相匹配的常规表达式转换为终端自动,然后转换自动,将每个接受状态转换为不接受,反之亦然,然后将结果的FA转换为常规表达式。

grep -P '^((?!hede).)*$' input

^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

^hede$(*SKIP)(*F)|^.*$

这将完全滑动包含准确的线条的线条,并匹配所有剩下的线条。

演示

符号前的部分. 符号不应匹配. ^hede$(*SKIP)(*F) 符号后的部分. 符号应匹配。

第一部分

^hede$(*SKIP)(*F)

解释:

因此,包含字符串的线条将被匹配. 一旦雷格斯发动机看到以下 (*SKIP)(*F)(注:你可以写 (*F)作为 (*FAIL))字符,它滑动并使匹配失败。

第2部分

^.*$

解释: