4893

我知道可以匹配一个单词,然后使用其他工具(例如grep -v)反转匹配项。但是,是否可以匹配不包含特定单词的行,例如hede,使用正则表达式?

输入:

hoho
hihi
haha
hede

代码:

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

期望的输出:

hoho
hihi
haha
4

31 回答 31

6766

正则表达式不支持反向匹配的概念并不完全正确。您可以通过使用负面环视来模仿这种行为:

^((?!hede).)*$

非捕获变体:

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

上面的正则表达式将匹配任何字符串,或没有换行符的行,包含(子)字符串“hede”。如前所述,这不是正则表达式“擅长”(或应该做)的事情,但仍然可能的。

如果您还需要匹配换行符,请使用DOT-ALL 修饰符s(以下模式中的尾随):

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

或内联使用它:

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

(其中/.../是正则表达式分隔符,即不是模式的一部分)

如果 DOT-ALL 修饰符不可用,您可以使用字符类模仿相同的行为[\s\S]

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

解释

字符串只是一个n字符列表。在每个字符之前和之后,都有一个空字符串。所以一个n字符列表将n+1有空字符串。考虑字符串"ABhedeCD"

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
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's 是空字符串。正则表达式(?!hede).向前看是否没有子字符串"hede"可以看到,如果是这样(所以看到了其他东西),那么.(dot) 将匹配除换行符之外的任何字符。环视也称为零宽度断言,因为它们不消耗任何字符。他们只断言/验证某些东西。

因此,在我的示例中,在(点)使用字符之前,首先验证每个空字符串以查看是否没有"hede"前面的内容。.正则表达式(?!hede).只会执行一次,因此它被包装在一个组中,并重复零次或多次:((?!hede).)*. 最后,锚定输入的开始和结束以确保消耗整个输入:^((?!hede).)*$

如您所见,输入"ABhedeCD"将失败,因为 on ,正e3表达式(?!hede)失败(前面有!)。 "hede"

于 2009-01-02T09:55:05.323 回答
850
于 2011-03-17T04:21:26.613 回答
230

如果你只是将它用于 grep,你可以使用它grep -v hede来获取所有不包含 hede 的行。

ETA 哦,重读这个问题,grep -v可能就是您所说的“工具选项”。

于 2009-01-02T07:41:22.597 回答
208

回答:

^((?!hede).)*$

解释:

^字符串的开头, (分组并捕获到\1(0次或多次(匹配最大可能)),
(?!向前看是否有,

hede你的弦,

)前瞻结束, .除 \n 之外的任何字符
)*,\1 结束(注意:因为您在此捕获中使用量词,所以只有捕获模式的最后一次重复将存储在 \1 中)
$在可选 \n 之前,和字符串的结尾

于 2014-05-10T16:36:11.620 回答
112

给出的答案非常好,只是一个学术观点:

理论计算机科学意义上的正则表达式不能这样做。对他们来说,它必须看起来像这样:

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

这只会进行完全匹配。为子比赛做这件事会更尴尬。

于 2011-09-02T15:53:15.993 回答
74

如果您希望正则表达式测试仅在整个字符串匹配时失败,则以下操作将起作用:

^(?!hede$).*

例如——如果你想允许除“foo”之外的所有值(即“foofoo”、“barfoo”和“foobar”将通过,但“foo”将失败),使用:^(?!foo$).*

当然,如果您要检查是否完全相等,在这种情况下,更好的通用解决方案是检查字符串是否相等,即

myStr !== 'foo'

如果您需要任何正则表达式功能(这里是不区分大小写和范围匹配),您甚至可以将否定置于测试之外:

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

但是,在需要正则表达式测试的情况下(可能通过 API),此答案顶部的正则表达式解决方案可能会有所帮助。

于 2013-01-03T21:22:09.910 回答
67

FWIW,由于正则语言(又名理性语言)在互补下是封闭的,所以总是有可能找到否定另一个表达式的正则表达式(又名有理表达式)。但实现这一点的工具并不多。

Vcsn支持此运算符(它表示{c},后缀)。

您首先定义表达式的类型:标签是lal_char要从a中选择z的字母( :true这个词被接受,,false被拒绝。

在 Python 中:

In [5]: import vcsn
        c = vcsn.context('lal_char(a-z), b')
        c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} → 

然后你输入你的表达式:

In [6]: e = c.expression('(hede){c}'); e
Out[6]: (hede)^c

将此表达式转换为自动机:

In [7]: a = e.automaton(); a

对应的自动机

最后,将此自动机转换回一个简单的表达式。

In [8]: print(a.expression())
        \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

其中+通常表示为|\e表示空词,[^]通常写成.(任何字符)。所以,稍微重写一下()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*

您可以在此处查看此示例,并在此处在线尝试 Vcsn 。

于 2015-08-05T07:02:36.410 回答
62

这里很好地解释了为什么否定任意正则表达式并不容易。不过,我必须同意其他答案:如果这不是一个假设性问题,那么正则表达式在这里不是正确的选择。

于 2009-01-02T08:03:06.717 回答
59

使用负前瞻,正则表达式可以匹配不包含特定模式的内容。Bart Kiers 对此进行了回答和解释。很好的解释!

但是,根据 Bart Kiers 的回答,前瞻部分将在匹配任何单个字符时提前测试 1 到 4 个字符。我们可以避免这种情况,让lookahead部分检查整个文本,确保没有'hede',然后正常部分(.*)可以一次吃掉整个文本。

这是改进的正则表达式:

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

请注意,负前瞻部分中的 (*?) 惰性量词是可选的,您可以使用 (*) 贪婪量词,具体取决于您的数据:如果 'hede' 确实存在并且在文本的前半部分,则惰性量词可以更快;否则,贪心量词会更快。但是,如果不存在“hede”,则两者都将同样缓慢。

这是演示代码

有关前瞻的更多信息,请查看精彩文章:掌握前瞻和后瞻

另外,请查看RegexGen.js,这是一个有助于构建复杂正则表达式的 JavaScript 正则表达式生成器。使用 RegexGen.js,您可以以更易读的方式构造正则表达式:

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()
);
于 2014-07-14T18:21:55.397 回答
47

基准

我决定评估一些提供的选项并比较它们的性能,并使用一些新功能。.NET 正则表达式引擎的基准测试:http ://regexhero.net/tester/

基准文本:

前 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: ^(?>[^R]+|R(?!egex Hero))*$             6.137   // Lookahead only on the right first letter
04: ^(?>(?:.*?Regex Hero)?)^.*$             7.426   // Match the word and check if you're still at linestart
05: ^(?(?=.*?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 不支持动作动词(*FAIL 等),我无法测试解决方案 P1 和 P2。

概括:

我尝试测试大多数建议的解决方案,某些词可能会进行一些优化。例如,如果搜索字符串的前两个字母不相同,则可以将答案 03 扩展为 ^(?>[^R]+|R+(?!egex Hero))*$导致小的性能增益。

但总体上最具可读性和性能方面最快的解决方案似乎是使用条件语句的 05 或使用所有格量词的 04。我认为 Perl 解决方案应该更快,更容易阅读。

于 2014-08-13T14:58:27.443 回答
34

不是正则表达式,但我发现使用带有管道的串行 grep 来消除噪音是合乎逻辑且有用的。

例如。搜索没有所有注释的 apache 配置文件-

grep -v '\#' /opt/lampp/etc/httpd.conf      # this gives all the non-comment lines

grep -v '\#' /opt/lampp/etc/httpd.conf |  grep -i dir

串行grep的逻辑是(不是注释)和(匹配目录)

于 2011-02-23T14:00:23.863 回答
31

这样,您可以避免在每个位置上测试前瞻:

/^(?:[^h]+|h++(?!ede))*+$/

相当于(对于.net):

^(?>(?:[^h]+|h+(?!ede))*)$

老答案:

/^(?>[^h]+|h+(?!ede))*$/
于 2013-04-14T03:04:42.320 回答
30

上述(?:(?!hede).)*很棒,因为它可以锚定。

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

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

但在这种情况下,以下内容就足够了:

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

这种简化已经准备好添加“AND”子句:

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same
于 2016-08-23T00:03:27.183 回答
24

由于没有其他人直接回答所提出的问题我会这样做。

答案是使用 POSIX grep,不可能从字面上满足这个要求:

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

原因是 POSIXgrep只需要使用Basic Regular Expressions,它们根本不足以完成该任务(由于缺乏交替,它们无法解析所有正则语言)。

但是,GNUgrep实现了允许它的扩展。特别\|是在 GNU 的 BRE 实现中的交替操作符。如果您的正则表达式引擎支持交替、括号和 Kleene 星号,并且能够锚定到字符串的开头和结尾,那么您就可以使用这种方法。但是请注意[^ ... ],除了这些之外,负集非常方便,因为否则,您需要用(a|b|c| ... )列出不在集合中的每个字符的形式的表达式替换它们,这非常乏味且过长,如果整个字符集是Unicode。

多亏了形式语言理论,我们才能看到这样的表达方式。使用 GNU grep,答案将类似于:

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

(在Grail中找到并进行了一些进一步的手工优化)。

您还可以使用实现扩展正则表达式的工具,例如egrep,摆脱反斜杠:

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

这是一个测试它的脚本(注意它testinput.txt在当前目录中生成一个文件)。提出的几个表达式未通过此测试。

#!/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 转换回一个正则表达式。

正如大家所注意到的,如果你的正则表达式引擎支持负前瞻,那么正则表达式就会简单得多。例如,使用 GNU grep:

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

但是,这种方法的缺点是需要回溯正则表达式引擎。这使得它不适合使用像RE2这样的安全正则表达式引擎的安装,这是在某些情况下更喜欢生成方法的原因之一。

使用 Kendall Hopkins 出色的FormalTheory库,用 PHP 编写,它提供类似于 Grail 的功能,以及我自己编写的简化器,我已经能够编写一个负正则表达式的在线生成器,给定输入短语(只有字母数字和空格当前支持的字符):http ://www.formauri.es/personal/pgimeno/misc/non-match-regex/

因为hede它输出:

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

相当于上面的。

于 2016-12-06T21:24:15.930 回答
23

这是我的做法:

^[^h]*(h(?!ede)[^h]*)*$

比其他答案更准确、更有效。它实现了 Friedl 的“展开循环”效率技术,并且需要更少的回溯。

于 2013-12-20T03:03:57.497 回答
23

在我看来,一个更易读的最佳答案变体:

^(?!.*hede)

基本上,“当且仅当它没有'hede'时在行的开头匹配” - 所以要求几乎直接翻译成正则表达式。

当然,可能有多个失败要求:

^(?!.*(hede|hodo|hada))

详细信息: ^ 锚确保正则表达式引擎不会在字符串中的每个位置重试匹配,这将匹配每个字符串。

开头的 ^ 锚点表示该行的开头。grep 工具一次匹配每一行,在您使用多行字符串的上下文中,您可以使用“m”标志:

/^(?!.*hede)/m # JavaScript syntax

或者

(?m)^(?!.*hede) # Inline flag
于 2018-11-24T18:26:48.317 回答
20

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

例如,一个字符串:

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

不使用:

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

采用:

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

注意"(?!bbb)."既不是后视也不是前瞻,它是当前的,例如:

"(?=abc)abcde", "(?!abc)abcde"
于 2012-03-23T07:24:34.683 回答
19

另一种选择是添加一个正向预测并检查hede输入行中是否存在任何位置,然后我们将否定它,表达式类似于:

^(?!(?=.*\bhede\b)).*$

与单词边界。


该表达式在regex101.com的右上角面板上进行了说明,如果您希望探索/简化/修改它,并且在此链接中,您可以查看它如何与一些示例输入匹配,如果您愿意的话。


正则表达式电路

jex.im可视化正则表达式:

在此处输入图像描述

于 2019-08-01T02:36:22.530 回答
15

OP 没有指定或Tag帖子指示将在其中使用正则表达式的上下文(编程语言、编辑器、工具)。

对我来说,有时我需要在使用Textpad.

Textpad支持一些Regex,但不支持lookahead或lookbehind,所以需要几步。

如果我想保留所有包含字符串的行hede,我会这样做:

1. 搜索/替换整个文件以在包含任何文本的每一行的开头添加一个唯一的“标签”。

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2.删除所有包含字符串的行hede(替换字符串为空):

    Search string:<@#-unique-#@>.*hede.*\n  
    Replace string:<nothing>  
    Replace-all  

3.此时,所有剩余的行都不包含字符串hede。从所有行中删除唯一的“标签”(替换字符串为空):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

hede现在,您拥有删除 了包含该字符串的所有行的原始文本。


如果我只想对包含字符串的行执行其他操作,我会这样做:hede

1. 搜索/替换整个文件以在包含任何文本的每一行的开头添加一个唯一的“标签”。

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2.对于所有包含字符串的行hede,删除唯一的“标签”:

    Search string:<@#-unique-#@>(.*hede)
    Replace string:\1  
    Replace-all  

3.此时,所有以唯一“Tag”开头的行,都不要包含字符串hede。我现在可以只对那些行做一些别的事情。

4. 完成后,我从所有行中删除唯一的“标签”(替换字符串为空):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  
于 2013-04-26T22:28:37.557 回答
13

自 ruby​​-2.4.1 引入以来,我们可以在 Ruby 的正则表达式中使用新的Absent Operator

来自官方文档

(?~abc) matches: "", "ab", "aab", "cccc", etc.
It doesn't match: "abc", "aabc", "ccccabc", etc.

因此,在您的情况下^(?~hede)$为您完成工作

2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)}
 => ["hoho", "hihi", "haha"]
于 2017-03-23T13:42:32.337 回答
11

通过 PCRE 动词(*SKIP)(*F)

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

这将完全跳过包含确切字符串hede并匹配所有剩余行的行。

演示

部分执行:

让我们通过将其分为两部分来考虑上述正则表达式。

  1. |符号前的部分。部分不应该匹配

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

    ^.*$
    

第1部分

正则表达式引擎将从第一部分开始执行。

^hede$(*SKIP)(*F)

解释:

  • ^断言我们处于起步阶段。
  • hede匹配字符串hede
  • $断言我们在行尾。

所以包含字符串的hede行将被匹配。一旦正则表达式引擎看到以下(*SKIP)(*F)注意:您可以写(*F)(*FAIL))动词,它就会跳过并使匹配失败。|在 PCRE 动词旁边添加了称为更改或逻辑 OR 运算符,它反过来匹配所有行上每个字符之间存在的所有边界,但该行包含确切的字符串hede在此处查看演示。也就是说,它尝试匹配剩余字符串中的字符。现在将执行第二部分中的正则表达式。

第2部分

^.*$

解释:

  • ^ 断言我们处于起步阶段。即,它匹配除该行中的行之外的所有行开头hede在此处查看演示。
  • .*在多行模式下,.将匹配除换行符或回车符之外的任何字符。并且*会重复前一个字符零次或多次。所以.*会匹配整条线。在此处查看演示。

    嘿为什么你添加 .* 而不是 .+ ?

    因为.*会匹配一个空白行但.+不会匹配一个空白。我们要匹配所有行,除了hede输入中可能还有空行。所以你必须使用.*而不是.+. .+会重复前一个字符一次或多次。看这里.*匹配一个空行。

  • $此处不需要行尾锚。

于 2014-10-09T07:00:55.703 回答
8

TXR 语言支持正则表达式否定。

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

一个更复杂的例子:匹配所有以 开头a和结尾z但不包含子字符串的行hede

$ 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

正则表达式否定本身并不是特别有用,但是当你也有交集时,事情会变得有趣,因为你有一套完整的布尔集操作:你可以表达“匹配这个的集合,除了匹配那个的东西”。

于 2014-06-25T01:23:45.163 回答
8

您的代码中的两个正则表达式可能更易于维护,一个进行第一个匹配,然后如果匹配,则运行第二个正则表达式以检查您希望阻止的异常情况,^.*(hede).*然后在您的代码中具有适当的逻辑。

好的,我承认这并不是对发布的问题的真正答案,它也可能比单个正则表达式使用更多的处理。但是对于来这里寻找异常情况的快速紧急修复的开发人员来说,这个解决方案不容忽视。

于 2015-02-18T11:45:28.343 回答
6

以下功能将帮助您获得所需的输出

<?PHP
      function removePrepositions($text){

            $propositions=array('/\bfor\b/i','/\bthe\b/i'); 

            if( count($propositions) > 0 ) {
                foreach($propositions as $exceptionPhrase) {
                    $text = preg_replace($exceptionPhrase, '', trim($text));

                }
            $retval = trim($text);

            }
        return $retval;
    }


?>
于 2016-12-21T04:55:17.550 回答
6

如果您尝试匹配包含字符串X但不包含字符串Y的整行,我想添加另一个示例。

例如,假设我们要检查我们的 URL / 字符串是否包含“ taste-treats ”,只要它在任何地方都不包含“ chocolate ”。

这个正则表达式模式可以工作(也可以在 JavaScript 中工作)

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

(例如全局,多行标志)

交互式示例:https ://regexr.com/53gv4

火柴

(这些网址包含“tasty-treats”,也不包含“chocolate”)

  • example.com/tasty-treats/strawberry-ice-cream
  • example.com/desserts/tasty-treats/banana-pudding
  • example.com/tasty-treats-overview

不匹配

(这些网址在某处包含“巧克力” - 因此即使它们包含“美味佳肴”,它们也不会匹配)

  • example.com/tasty-treats/chocolate-cake
  • example.com/home-cooking/oven-roasted-chicken
  • example.com/tasty-treats/banana-chocolate-fudge
  • example.com/desserts/chocolate/tasty-treats
  • example.com/chocolate/tasty-treats/desserts
于 2020-04-28T18:53:32.600 回答
6

只要您正在处理线条,只需标记否定匹配项并针对其余部分

事实上,我在 sed 中使用了这个技巧,因为^((?!hede).)*$它看起来不支持。

对于所需的输出

  1. 标记否定匹配:(例如带有 的行hede),使用完全不包含在整个文本中的字符。为此,表情符号可能是一个不错的选择。

    s/(.*hede)/\1/g
    
  2. 定位其余部分(未标记的字符串:例如没有 的行hede)。假设您只想保留目标并删除其余部分(如您所愿):

    s/^.*//g
    

为了更好的理解

假设您要删除目标

  1. 标记否定匹配:(例如带有 的行hede),使用完全不包含在整个文本中的字符。为此,表情符号可能是一个不错的选择。

    s/(.*hede)/\1/g
    
  2. 定位其余部分(未标记的字符串:例如没有 的行hede)。假设您要删除目标

    s/^[^].*//g
    
  3. 删除标记:

    s///g
    
于 2020-06-15T11:02:11.627 回答
5

^((?!hede).)*$是一个优雅的解决方案,除了因为它消耗字符,您将无法将它与其他标准结合起来。例如,假设您想检查“hede”的不存在和“haha”的存在。此解决方案将起作用,因为它不会消耗字符:

^(?!.*\bhede\b)(?=.*\bhaha\b) 
于 2019-03-26T12:21:23.923 回答
3

如何使用 PCRE 的回溯控制动词来匹配不包含单词的行

这是我以前从未见过的一种方法:

/.*hede(*COMMIT)^|/

这个怎么运作

首先,它试图在该行的某处找到“hede”。如果成功,此时(*COMMIT)会告诉引擎,不仅在失败的情况下不要回溯,而且在这种情况下也不要尝试任何进一步的匹配。然后,我们尝试匹配一些不可能匹配的东西(在本例中为^)。

如果一行不包含“hede”,那么第二个备选方案,一个空的子模式,成功地匹配主题字符串。

这种方法并不比负前瞻更有效,但我想我会把它放在这里,以防有人觉得它很漂亮,并发现它可以用于其他更有趣的应用程序。

于 2017-10-11T10:12:31.233 回答
1

一个更简单的解决方案是使用 not 运算符

您的if语句需要匹配“包含”而不是“排除”。

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

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

我相信 RegEx 的设计者预料到了 not 运算符的使用。

于 2016-09-13T13:52:13.023 回答
1

也许你会在谷歌上找到这个,同时尝试编写一个能够匹配包含子字符串的行段(而不是整行)的正则表达式。我花了一段时间才弄清楚,所以我会分享:

给定一个字符串: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

我想匹配<span>不包含子字符串“bad”的标签。

/<span(?:(?!bad).)*?>将匹配<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\">"]
于 2018-04-25T18:15:32.483 回答
1

使用ConyEdit,您可以使用命令行cc.gl !/hede/获取不包含正则表达式匹配的行,或使用命令行cc.dl /hede/删除包含正则表达式匹配的行。他们有相同的结果。

于 2018-07-09T17:08:32.053 回答