一个永远不会被任何东西匹配的正则表达式

F.P*_*F.P 120 regex complexity-theory dictionary

这可能听起来像一个愚蠢的问题,但我与我的一些开发人员进行了长时间的谈话,这听起来像是一件有趣的事情.

所以; 你的想法是什么 - 正则表达式是什么样的,永远不会被任何字符串匹配!

编辑:我为什么要这个?好吧,首先是因为我发现想到这样一个表达式很有趣,其次因为我需要它来制作一个脚本.

在该脚本中,我将字典定义为Dictionary<string, Regex>.如您所见,它包含一个字符串和一个表达式.

基于该字典,我创建的方法都使用这个字典作为他们应该如何完成工作的参考,其中一个匹配正则表达式与解析的日志文件.

如果表达式匹配,Dictionary<string, long>则为另一个表达式添加表达式返回的值.因此,为了捕获与字典中的表达式不匹配的任何日志消息,我创建了一个名为"unknown"的新组.

对于这个组,添加了与其他任何东西不匹配的所有内容.但是为了防止"未知"表达式(偶然)不匹配日志消息,我不得不创建一个绝对不会匹配的表达式,无论我给它什么字符串.

因此,你有理由这个"不是一个真正的问题"......

Ale*_*lli 74

杠杆negative lookahead:

>>> import re
>>> x=r'(?!x)x'
>>> r=re.compile(x)
>>> r.match('')
>>> r.match('x')
>>> r.match('y')
Run Code Online (Sandbox Code Playgroud)

这个RE在术语上是矛盾的,因此永远不会匹配任何东西.

注意:
在Python中,re.match()隐式地将一个字符串开头的anchor(\A)添加到正则表达式的开头.此锚点对性能很重要:没有它,将扫描整个字符串.那些不使用Python的人会想要明确地添加锚点:

\A(?!x)x
Run Code Online (Sandbox Code Playgroud)

  • 看起来效果很好。但如果只是(?!)呢?既然 () 总是匹配,难道 (?!) 不能保证永远不匹配吗? (3认同)
  • @Peter,是的,如果Python接受该语法(并且最近的版本似乎),那么它也会自相矛盾.另一个想法(不太优雅,但你得到的想法越多,你就越有可能找到一个在所有感兴趣的RE引擎上工作):`r'a\bc'`,寻找一个字母边界,立即被字母包围双方(变体:两边都是非字符). (2认同)
  • 那可能很慢`perl -Mre = debug -e'$ _ = xx 8; /(?x)的X /'`.您可以通过将其锚定在开头`\ A(?!x)x`或结尾`(?!x)x\z`来加快速度.`perl -Mre = debug -e'$ _ = xx 8; /(?x)的X\Z /; /\A(?!X)X /'` (2认同)

Fer*_*yer 62

这实际上非常简单,虽然它取决于implementation/flags*:

$a
Run Code Online (Sandbox Code Playgroud)

a在字符串结尾后匹配一个字符.祝好运.

警告:
此表达式很昂贵 - 它将扫描整行,找到行尾锚点,然后才找到a并返回负匹配.(有关详细信息,请参阅下面的评论.)


*最初我没有考虑多线模式正则表达式,其中$也匹配线的末尾.事实上,它会在换行符之前匹配空字符串,所以像往常一样的普通字符a永远不会出现$.

  • 这个表达式很昂贵 - 它将扫描整行,找到行尾锚点,然后才找不到"a"并返回否定匹配.我看到扫描~275k行文件需要大约480ms.相反的"a ^"大约需要相同的时间,即使它看起来更有效.另一方面,负向前瞻不需要扫描任何东西:"(?!x)x"(任何未跟随x后跟x都没有的东西),大约需要30ms,或者不到7%的时间.(用gnu时间和egrep测量) (48认同)
  • 在 POSIX BRE 语法中,`$a` 将匹配文字文本 `$a`,因为 `$` 作为该模式中的锚点是无效的。 (2认同)

Mar*_*ers 35

错过了一个:

^\b$
Run Code Online (Sandbox Code Playgroud)

它无法匹配,因为空字符串不包含单词边界.在Python 2.5中测试.

  • 这是最好的答案.它不使用前瞻,在一些正则表达式实现下不会中断,不使用特定字符(例如'a'),并且在最多3个处理步骤(根据regex101.com)中失败而不扫描整个输入字符串.这一点也很容易理解. (6认同)

Ama*_*osh 34

环视四周:

(?=a)b

对于正则表达式新手:正向前看(?=a)确保下一个字符是a,但不会更改搜索位置(或在匹配的字符串中包含"a").现在确认了下一个字符a,regex(b)的剩余部分仅在下一个字符匹配时才匹配b.因此,此正则表达式匹配只有一个字符既ab在同一时间.

  • ... 你的举动。 (2认同)

P S*_*ved 29

a\bc,其中\b是一个与字边界匹配的零宽度表达式.

它不能出现在一个单词的中间,我们强迫它.


Kni*_*nio 20

$.

.^

$.^

(?!)

  • 这已经测试过了吗?我假设“^”仅作为正则表达式的第一个字符具有特殊含义,而“$”仅在正则表达式的末尾具有特殊含义,除非正则表达式是多行表达式。 (2认同)

Bra*_*ert 11

最大匹配

a++a
Run Code Online (Sandbox Code Playgroud)

至少有一个a跟随任意数量a的,没有回溯.然后尝试再匹配一个a.

或独立子表达式

这相当于放入a+一个独立的子表达式,然后是另一个子表达式a.

(?>a+)a
Run Code Online (Sandbox Code Playgroud)


Kan*_*oon 10

Perl 5.10支持称为"动词"的特殊控制字,它按(*...)顺序包含在内.(与(?...)特殊序列比较.)其中,它包括立即从正则表达式返回的(*FAIL)动词.

请注意,动词也会在不久之后在PCRE中实现,因此您也可以使用PCRE库在PHP或其他语言中使用它们.(但是你不能用Python或Ruby.他们使用自己的引擎.)


Kob*_*obi 9

\B\b
Run Code Online (Sandbox Code Playgroud)

\b匹配单词边界 - 字母与非字母(或字符串边界)之间的位置.
\B是它的补充 - 它匹配两个字母之间或非字母之间的位置.

他们在一起无法匹配任何位置.

也可以看看:


Bob*_*Bob 8

$^或者怎么样(?!)? 

  • 也许他的意思是`(?!)` - 一个空字符串的负向前瞻.但是一些正则表达式的味道也会将其视为语法错误. (3认同)
  • 该表达式将以`^`匹配行的开始和`$`结束行的方式匹配换行符。 (2认同)

Jer*_*olz 8

这似乎有效:

$.
Run Code Online (Sandbox Code Playgroud)

  • 它将匹配点匹配 - 换行模式. (8认同)
  • 这与Ferdinand Beyer的例子相似. (2认同)

Ada*_*son 5

最快的将是:

r = re.compile(r'a^')
r.match('whatever')
Run Code Online (Sandbox Code Playgroud)

“ a”可以是任何非特殊字符(“ x”,“ y”)。Knio的实现可能会更纯净,但是对于所有不以您选择的任何字符开头而不是'a'开头的字符串来说,这种方法都会更快,因为在这种情况下,它将不匹配第一个字符,而不是第二个字符。

  • 这真的有效吗?如果是这样,谁决定放弃Unix?在Unix正则表达式中,“ ^”仅作为第一个字符是特殊的,与“ $”类似。使用任何Unix工具,该regexp都将匹配包含文字字符串`a ^`的所有内容。 (3认同)

Bar*_*ers 5

[^\d\D](?=a)ba$aa^a


und*_*ned 5

这不适用于 Python 和许多其他语言,但在 Javascript 正则表达式中,[]是无法匹配的有效字符类。因此,无论输入什么,以下内容都应该立即失败:

var noMatch = /^[]/;
Run Code Online (Sandbox Code Playgroud)

我更喜欢它,/$a/因为对我来说,它清楚地传达了它的意图。至于何时需要它,我需要它,因为我需要基于用户输入的动态编译模式的后备。当模式无效时,我需要将其替换为不匹配的模式。简化后,它看起来像这样:

try {
    var matchPattern = new RegExp(someUserInput);
}
catch (e) {
    matchPattern = noMatch;
}
Run Code Online (Sandbox Code Playgroud)


fil*_*rem 5

这么多好的答案!

与 @nivk 的答案类似,我想分享 Perl 对于不同变体的不匹配正则表达式的性能比较。

  1. 输入:伪随机 ascii 字符串(25,000 行不同的行,长度 8-16):

正则表达式速度:

Total for   \A(?!x)x: 69.675450 s, 1435225 lines/s
Total for       a\bc: 71.164469 s, 1405195 lines/s
Total for    (?>a+)a: 71.218324 s, 1404133 lines/s
Total for       a++a: 71.331362 s, 1401907 lines/s
Total for         $a: 72.567302 s, 1378031 lines/s
Total for     (?=a)b: 72.842308 s, 1372828 lines/s
Total for     (?!x)x: 72.948911 s, 1370822 lines/s
Total for       ^\b$: 79.417197 s, 1259173 lines/s
Total for         $.: 88.727839 s, 1127041 lines/s
Total for       (?!): 111.272815 s, 898692 lines/s
Total for         .^: 115.298849 s, 867311 lines/s
Total for    (*FAIL): 350.409864 s, 285380 lines/s
Run Code Online (Sandbox Code Playgroud)
  1. 输入:/usr/share/dict/words(100,000 个英文单词)。

正则表达式速度:

Total for   \A(?!x)x: 128.336729 s, 1564805 lines/s
Total for     (?!x)x: 132.138544 s, 1519783 lines/s
Total for       a++a: 133.144501 s, 1508301 lines/s
Total for    (?>a+)a: 133.394062 s, 1505479 lines/s
Total for       a\bc: 134.643127 s, 1491513 lines/s
Total for     (?=a)b: 137.877110 s, 1456528 lines/s
Total for         $a: 152.215523 s, 1319326 lines/s
Total for       ^\b$: 153.727954 s, 1306346 lines/s
Total for         $.: 170.780654 s, 1175906 lines/s
Total for       (?!): 209.800379 s, 957205 lines/s
Total for         .^: 217.943800 s, 921439 lines/s
Total for    (*FAIL): 661.598302 s, 303540 lines/s
Run Code Online (Sandbox Code Playgroud)

(Intel i5-3320M 上的 Ubuntu、Linux 内核 4.13、Perl 5.26)


aeo*_*eon 5

空正则表达式

永远不匹配任何内容的最佳正则表达式是空正则表达式。但我不确定所有正则表达式引擎都会接受这一点。

不可能的正则表达式

另一个解决方案是创建一个不可能的正则表达式。我发现无论$-^文本大小如何,只需要两个步骤即可计算(https://regex101.com/r/yjcs1Z/1)。

以供参考:

  • $^$.需要 36 个步骤来计算 -> O(1)
  • \b\B在我的样本上需要 1507 步,并且随着字符串中字符数的增加而增加 -> O(n)

关于这个问题的更受欢迎的帖子:


归档时间:

查看次数:

15362 次

最近记录:

6 年,4 月 前