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

入口:

hoho
hihi
haha
hede

代码:

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

所需的产量:

hoho
hihi
haha

当前回答

此前提到的(?(?!)*是很棒的,因为它可以被 anchored。

^(?:(?!hede).)*$               # A line without hede

foo(?:(?!hede).)*bar           # foo followed by bar, without hede between them

但在这种情况下,以下几点就足够了:

^(?!.*hede)                    # A line without hede

此简化已准备好添加“和”条款:

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same

其他回答

我想添加另一个例子,如果你试图匹配一个包含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

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

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

根据字符串: <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\">"]

如果你想匹配一个字符,否认类似于否认字符类的单词:

例如,一条线:

<?
$str="aaa        bbb4      aaa     bbb7";
?>

不要使用:

<?
preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches);
?>

使用:

<?
preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches);
?>

警告“(?!bbb.)”不是 lookbehind 或 lookahead,它是 lookcurrent,例如:

"(?=abc)abcde", "(?!abc)abcde"

如果您希望 regex 测试只会失败,如果整个序列相匹配,则下列内容将工作:

^(?!hede$).*

例如 - 如果你想允许除了“foo”以外的所有值(即“foofoo”,“barfoo”和“foobar”将通过,但“foo”将失败),请使用: ^(?!foo$)。

当然,如果你正在检查准确的平等,在这种情况下,一个更好的总体解决方案是检查序列平等,也就是说。

myStr !== 'foo'

您甚至可以将拒绝置于测试之外,如果您需要任何 regex 功能(这里,案例不敏感性和范围匹配):

!/^[a-f]oo$/i.test(myStr)

但是,这个答案的顶部的 regex 解决方案在需要积极的 regex 测试的情况下可能有用(可能是通过 API)。