正则表达式匹配不包含单词的行

时间:2009-01-02 07:30:16

标签: regex regex-negation regex-lookarounds regex-greedy regex-group

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

输入:

hoho
hihi
haha
hede

代码:

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

期望的输出:

hoho
hihi
haha

31 个答案:

答案 0 :(得分:5356)

正则表达式不支持逆匹配的概念并不完全正确。您可以使用负面外观来模仿此行为:

^((?!hede).)*$

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

如果您还需要匹配换行符,请使用DOT-ALL modifier(以下模式中的尾随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是空字符串。正则表达式(?!hede).向前看,看看是否没有子串"hede",如果是这种情况(因此看到其他内容),那么.(点)将匹配除换行符之外的任何字符。环视也称为零宽度断言,因为它们不会消耗任何字符。他们只断言/验证某些东西。

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

正如您所看到的,输入"ABhedeCD"将失败,因为在e3上,正则表达式(?!hede)失败(前面有 "hede" !)。

答案 1 :(得分:670)

请注意的解决方案不“hede”开头

^(?!hede).*$

通常比 “hede”的解决方案更有效

^((?!hede).)*$

前者仅在输入字符串的第一个位置检查“hede”,而不是在每个位置检查。

答案 2 :(得分:188)

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

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

答案 3 :(得分:140)

<强>答案:

^((?!hede).)*$

<强>解释

^字符串的开头, (组并捕获到\ 1(0次或更多次(匹配尽可能多的数量)),
(?!展望未来,看看是否有,

hede你的字符串,

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

答案 4 :(得分:96)

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

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

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

这只是完全匹配。为子匹配做这件事甚至会更加尴尬。

答案 5 :(得分:54)

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

^(?!hede$).*

e.g。 - 如果要允许除“foo”之外的所有值(即“foofoo”,“barfoo”和“foobar”将通过,但“foo”将失败),请使用:^(?!foo$).*

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

myStr !== 'foo'

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

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

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

答案 6 :(得分:53)

FWIW,由于常规语言(也称为理性语言)在互补下被关闭,因此总是可以找到否定另一个表达式的正则表达式(也称为理性表达式)。但实现这一目标的工具并不多。

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

首先定义表达式的类型:标签是字母(lal_char),例如从az选择(当使用互补时定义字母表当然是,非常重要),&#34;价值&#34;为每个单词计算的只是一个布尔值: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

Vcsn

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

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.)))).*

您可以看到此示例The corresponding automaton,并在线试用Vcsn here

答案 7 :(得分:50)

这里有a good explanation为什么否定任意正则表达式并不容易。我不得不同意其他答案:如果这不是一个假设的问题,那么正则表达式不是正确的选择。

答案 8 :(得分:41)

基准

我决定评估一些呈现的选项并比较它们的性能,以及使用一些新功能。 .NET Regex引擎的基准测试: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解决方案应该更快,更容易阅读。

答案 9 :(得分:41)

使用负向前瞻,正则表达式可以匹配不包含特定模式的内容。 Bart Kiers回答并解释了这一点。很棒的解释!

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

这是改进的正则表达式:

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

注意负前瞻部分中的(*?)延迟量词是可选的,您可以使用(*)贪心量词,取决于您的数据:如果'hede'确实存在并且在文本的开头一半,懒惰量词可以更快;否则,贪婪量词会更快。但是,如果'hede'不存在,两者都会相等。

这是demo code

有关前瞻的更多信息,请查看精彩的文章:Mastering Lookahead and Lookbehind

另外,请查看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()
);

答案 10 :(得分:32)

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

例如。搜索没有所有注释的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的逻辑是(不是注释)和(匹配dir)

答案 11 :(得分:29)

有了这个,你可以避免在每个位置测试前瞻:

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

相当于(for .net):

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

旧答案:

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

答案 12 :(得分:20)

前面提到的(?:(?!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

答案 13 :(得分:19)

我是这样做的:

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

比其他答案更准确,更有效率。它实现了Friedl的“unrolling-the-loop”效率技术,并且需要更少的回溯。

答案 14 :(得分:17)

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

例如,字符串:

<?
$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"

答案 15 :(得分:13)

OP未指定或 标记 帖子以指示将在其中使用正则表达式的上下文(编程语言,编辑器,工具)。

对我来说,我有时需要在使用 Textpad 编辑文件时执行此操作。

Textpad 支持某些正则表达式,但不支持前瞻或后瞻,因此需要几个步骤。

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

  

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

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

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

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

  

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

    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。此时,所有以唯一“标记”开头的行 不要 包含字符串 hede 。我现在可以将 Something Else 仅用于那些行。

  

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

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

答案 16 :(得分:10)

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

来自官方doc

(?~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"]

答案 17 :(得分:9)

由于没有其他人直接回答被问及的问题,我会这样做。

答案是,对于POSIX grep,不可能真正满足这个要求:

grep "Regex for doesn't contain hede" Input

原因是POSIX grep只需要与Basic Regular Expressions一起使用,它们不足以完成该任务(由于缺乏交替,它们无法解析常规语言)和分组)。

然而,GNU grep实现了允许它的扩展。特别是,\|是GNU实现BRE的交替运算符,\(\)是分组运算符。如果你的正则表达式引擎支持交替,负括号表达式,分组和Kleene星,并且能够锚定到字符串的开头和结尾,那么这就是这种方法所需要的。

使用GNU grep,它将类似于:

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

(找到Grail并进行一些进一步的优化)。

您还可以使用实现Extended Regular Expressions的工具(如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

更新:我最近发现了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?)?)?$

等同于上述。

答案 18 :(得分:9)

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

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

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

DEMO

执行部分:

让我们将上面的正则表达式分成两部分来考虑。

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

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

    ^.*$
    
  3. 第1部分

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

    ^hede$(*SKIP)(*F)
    

    <强>解释

    • ^断言我们刚开始。
    • hede匹配字符串hede
    • $断言我们在行尾。

    所以包含字符串hede的行将匹配。一旦正则表达式引擎看到以下(*SKIP)(*F)注意:您可以将(*F)写为(*FAIL) )动词,它会跳过并使匹配失败。 |在PCRE动词旁边添加了名为alteration或逻辑OR运算符,其中匹配所有行之间的所有边界,除了该行包含精确的字符串hede之外。请参阅演示here。也就是说,它尝试匹配剩余字符串中的字符。现在,第二部分中的正则表达式将被执行。

    第2部分

    ^.*$
    

    <强>解释

    • ^断言我们刚开始。即,它匹配除hede行中的那一行之外的所有行开头。请参阅演示here
    • .*在多行模式下,.将匹配除换行符或回车符之外的任何字符。 *将重复前一个字符零次或多次。所以.*会匹配整行。请参阅演示here

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

      因为.*会匹配一个空白行,但.+不匹配空白。我们希望匹配除hede之外的所有行,输入中也可能出现空行。因此,您必须使用.*代替.+.+会重复前一个字符一次或多次。请参阅.*与空白行here匹配。

    • $此处不需要行锚点结束。

答案 19 :(得分:8)

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

^(?!.*hede)

基本上,“如果且仅当行中没有'hede'时,才匹配该行的开头”-因此该要求几乎直接转换为regex。

当然,可能有多种故障要求:

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

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

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

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

(?m)^(?!.*hede) # Inline flag

答案 20 :(得分:7)

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

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

答案 21 :(得分:5)

TXR Language支持正则表达式否定。

$ 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

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

答案 22 :(得分:4)

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

<?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;
    }


?>

答案 23 :(得分:2)

另一种选择是添加正向的前瞻性并检查hehe是否在输入行中的任何地方,然后我们将其取反,其表达式类似于:

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

带有单词边界。


该表达式在regex101.com的右上角进行了解释,如果您想探索/简化/修改它,在this link中,您可以观察到它如何与某些示例输入匹配,如果你喜欢。


RegEx电路

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

enter image description here

答案 24 :(得分:2)

只要您要处理线,只需标记否定匹配并定位其余匹配

实际上,我将这个技巧与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
    

答案 25 :(得分:1)

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

以下是我以前没见过的方法:

/.*hede(*COMMIT)^|/

如何运作

首先,它试图找到&#34; hede&#34;在某个地方。如果成功,此时(*COMMIT)告诉引擎,不仅在发生故障时不回溯,而且在这种情况下也不再尝试进一步匹配。然后,我们尝试匹配一些不可能匹配的东西(在这种情况下,^)。

如果一行不包含&#34; hede&#34;然后第二个替代方案,一个空子模式,成功匹配主题字符串。

这种方法并不比负面前瞻更有效,但我想我只是把它扔在这里以防有人发现它很漂亮并且发现其用于其他更有趣的应用程序。

答案 26 :(得分:1)

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

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

我希望匹配不包含子字符串的<span>标记&#34; bad&#34;。

/<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\">"]

答案 27 :(得分:1)

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

例如,假设我们要检查我们的URL /字符串是否包含“ 好吃的食物”,只要它在任何地方都不包含“ 巧克力

此正则表达式模式可以使用(也可以在JavaScript中使用)

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

(例如全局,多行标志)

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

比赛

(这些网址包含“美味佳肴”,也不包含“巧克力”)

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

不匹配

(这些网址在某处包含“ chocolate”,因此即使它们包含“ tasty-treats”也不会匹配)

  • 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

答案 28 :(得分:0)

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

if 语句需要匹配&#34;包含&#34;并且不匹配&#34;排除&#34;。

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

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

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

答案 29 :(得分:0)

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

答案 30 :(得分:0)

^((?! hede)。)* $是一种优雅的解决方案,但由于它会消耗字符,因此您无法将其与其他条件结合使用。例如,假设您要检查是否不存在“ hede”和是否存在“ haha​​”。此解决方案将起作用,因为它不会消耗字符:

^(?!。 \ bhede \ b)(?=。 \ bhaha \ b)