一个任何东西都无法匹配的正则表达式

您的想法是什么-正则表达式看起来像什么,它永远不会被任何字符串匹配,永远!

编辑 : 为什么我想要这个?首先是因为我觉得这个表达很有趣其次是因为我需要它来写剧本。

在这个脚本中,我将字典定义为 Dictionary<string, Regex>,它包含一个字符串和一个表达式。

基于这个字典,我创建了一些方法,所有这些方法都使用这个字典作为它们应该如何工作的唯一参考,其中一个方法将正则表达式与解析后的日志文件进行匹配。

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

在这个组中添加了所有与其他组不匹配的内容。但是为了防止“未知”-表达式(偶然地)与日志消息不匹配,我必须创建一个几乎肯定永远不会匹配的表达式,无论我给它什么字符串。

28142 次浏览

$^或者 (?!)

'[^0-9a-zA-Z...]*'

并用所有可打印的符号替换...)。这是用于文本文件的。

这似乎行得通:

$.

这其实很简单,尽管它取决于实现/标志 * :

$a

将匹配字符串结束后的字符 a。祝你好运。

警告:
这个表达式代价很高——它将扫描整个行,找到行尾锚,只有在这样的情况下才不会找到 a并返回负匹配。(详情请参阅下面的评论。)


* 最初我没有考虑多行模式 regexp,其中 $也匹配一行的末尾。实际上,它会匹配空字符串 就在换行之前,所以像 a这样的普通字符永远不会出现在 $之后。

a\bc,其中 \b是匹配单词边界的零宽度表达式。

它不能出现在一个词的中间,这是我们强迫它出现的。

看看周围:

(?=a)b

对于正则表达式新手: 正面的前瞻 (?=a)确保下一个字符是 a,但不改变搜索位置(或包括“ a”在匹配的字符串)。现在确认下一个字符是 a,只有当下一个字符是 b时,正则表达式(b)的其余部分才匹配。因此,只有当一个字符同时是 ab时,这个正则表达式才匹配。

最大匹配

a++a

至少一个 a后面跟随任意数量的 a,没有回溯。然后尝试匹配一个更多的 a

或独立子表达式

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

(?>a+)a

也许是这个?

/$.+^/

如果不使用正则表达式,而是使用一个总是错误的 if 语句呢:

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}

杠杆作用 negative lookahead:

>>> import re
>>> x=r'(?!x)x'
>>> r=re.compile(x)
>>> r.match('')
>>> r.match('x')
>>> r.match('y')

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

注意:
在 Python 中,Re.match ()隐式地在正则表达式的开头添加一个字符串开头锚(\A)。此锚点对性能非常重要: 如果没有它,将扫描整个字符串。那些不使用 Python 的人会希望显式地添加锚:

\A(?!x)x

Python 不会接受它,但 Perl 会:

perl -ne 'print if /(w\1w)/'

这个正则表达式(理论上)应该尝试匹配无限(偶数)的 w,因为第一组(())递归到它自己。Perl 似乎没有发出任何警告,甚至在 use strict; use warnings;下也是如此,所以我假设它至少是有效的,并且我的(最小的)测试没有匹配任何东西,所以我将它提交给您的评论。

$.

.^

$.^

(?!)

最快的将是:

r = re.compile(r'a^')
r.match('whatever')

‘ a’可以是任何非特殊字符(‘ x’,‘ y’)。Knio 的实现可能会更加纯粹一些,但是对于所有字符串,如果不是以你选择的字符而不是以‘ a’开始,那么这个实现会更快,因为在这种情况下,它不会在第一个字符之后而不是第二个字符之后匹配。

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

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

我相信

\Z RE FAILS! \A

甚至包括正则表达式包含 MULTILINE、 DOTALL 等标志的情况。

>>> import re
>>> x=re.compile(r"\Z RE FAILS! \A")
>>> x.match('')
>>> x.match(' RE FAILS! ')
>>>

我相信(但我还没有对它进行基准测试) ,无论 \Z\A之间的字符串的长度(> 0)如何,故障发生的时间应该是常数。

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

不依赖于 regexp 实现的可移植解决方案是只使用常量 确保永远不会出现在日志消息中的字符串。例如,根据以下内容创建一个字符串:

cat /dev/urandom | hexdump | head -20
0000000 5d5d 3607 40d8 d7ab ce72 aae1 4eb3 ae47
0000010 c5e2 b9e8 910d a2d9 2eb3 fdff 6301 c85f
0000020 35d4 c282 e439 33d8 1c73 ca78 1e4d a569
0000030 8aca eb3c cbe4 aff7 d079 ca38 8831 15a5
0000040 818b 323f 0b02 caec f17f 387b 3995 88da
0000050 7b02 c80b 2d42 8087 9758 f56f b71f 0053
0000060 1501 35c9 0965 2c6e 03fe 7c6d f0ca e547
0000070 aba0 d5b6 c1d9 9bb2 fcd1 5ec7 ee9d 9963
0000080 6f0a 2c91 39c2 3587 c060 faa7 4ea4 1efd
0000090 6738 1a4c 3037 ed28 f62f 20fa 3d57 3cc0
00000a0 34f0 4bc2 3067 a1f7 9a87 086b 2876 1072
00000b0 d9e1 6b8f 5432 a60e f0f5 00b5 d9ef ed6f
00000c0 4a85 70ee 5ec4 a378 7786 927f f126 2ec2
00000d0 18c5 46fe b167 1ae6 c87c 1497 48c9 3c09
00000e0 8d09 e945 13ce 7da2 08af 1a96 c24c c022
00000f0 b051 98b3 2bf5 4d7d 5ec4 e016 a50d 355b
0000100 0e89 d9dd b153 9f0e 9a42 a51f 2d46 2435
0000110 ef35 17c2 d2aa 3cc7 e2c3 e711 d229 f108
0000120 324e 5d6a 650a d151 bc55 963f 41d3 66ee
0000130 1d8c 1fb1 1137 29b2 abf7 3af7 51fe 3cf4

当然,这不是智力上的挑战,更像是 管道胶带程序设计

new Regex(Guid.NewGuid().ToString())

创建一个只包含字母数字和“ -”(没有一个是正则表达式特殊字符)的模式,但是从统计学上来说,同一个字符串之前不可能出现在任何地方(因为这是 GUID 的全部意义所在)

被忽略的一点:

^\b$

它不能匹配,因为空字符串不包含单词边界。

\B\b

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

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

参见:

(*FAIL)

或者

(*F)

使用 PCRE 和 PERL,您可以使用这个回溯控制谓词来强制模式立即失败。

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

var noMatch = /^[]/;

我喜欢它比 /$a/更好,因为对我来说,它清楚地传达了它的意图。至于什么时候需要它,我需要它是因为我需要一个基于用户输入的动态编译模式的备份。当模式无效时,我需要用不匹配任何内容的模式替换它。简单来说,它看起来像这样:

try {
var matchPattern = new RegExp(someUserInput);
}
catch (e) {
matchPattern = noMatch;
}

在看到这些伟大的答案后,@ arantius 的评论(关于定时 $xx^(?!x)x)对目前接受的答案让我想要计时的一些解决方案给出迄今为止。

使用@arantius 的275k 行标准,我在 Python 中运行了以下测试(v3.5.2,IPython 6.2.1)。

TL; DR: 'x^''x\by'是最快的,至少是? 16倍,与@arantius 的发现相反,(?!x)x最慢的之一(? 37倍慢)。所以速度的问题当然取决于实现。如果速度对你来说很重要,在提交之前你自己在你想要的系统上测试一下。

更新: 在 'x^''a^'的时间上有明显的差异。请参阅 这个问题获得更多信息,以及之前用 a代替 x编辑较慢的计时。

In [1]: import re


In [2]: with open('/tmp/longfile.txt') as f:
...:     longfile = f.read()
...:


In [3]: len(re.findall('\n',longfile))
Out[3]: 275000


In [4]: len(longfile)
Out[4]: 24733175


In [5]: for regex in ('x^','.^','$x','$.','$x^','$.^','$^','(?!x)x','(?!)','(?=x)y','(?=x)(?!x)',r'x\by',r'x\bx',r'^\b$'
...: ,r'\B\b',r'\ZNEVERMATCH\A',r'\Z\A'):
...:     print('-'*72)
...:     print(regex)
...:     %timeit re.search(regex,longfile)
...:
------------------------------------------------------------------------
x^
6.98 ms ± 58.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
.^
155 ms ± 960 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x
111 ms ± 2.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.
111 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x^
112 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.^
113 ms ± 1.44 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$^
111 ms ± 839 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?!x)x
257 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?!)
203 ms ± 1.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?=x)y
204 ms ± 4.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?=x)(?!x)
210 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
x\by
7.41 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
x\bx
7.42 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
^\b$
108 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\B\b
387 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
\ZNEVERMATCH\A
112 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\Z\A
112 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

第一次运行这个命令时,我忘记了 raw 最后3个表达式,所以 '\b'被解释为 '\x08',退格字符。然而,令我惊讶的是,'a\x08c'比以前最快的成绩还要快!公平地说,它仍然会匹配该文本,但我认为它仍然值得注意,因为我不知道为什么它更快。

In [6]: for regex in ('x\by','x\bx','^\b$','\B\b'):
...:     print('-'*72)
...:     print(regex, repr(regex))
...:     %timeit re.search(regex,longfile)
...:     print(re.search(regex,longfile))
...:
------------------------------------------------------------------------
y 'x\x08y'
5.32 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
x 'x\x08x'
5.34 ms ± 66.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
$ '^\x08$'
122 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
None
------------------------------------------------------------------------
\ '\\B\x08'
300 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
None

我的测试文件是使用 “ ... 可读的内容和没有重复的行”公式创建的(在 Ubuntu 16.04上) :

$ ruby -e 'a=STDIN.readlines;275000.times do;b=[];rand(20).times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > /tmp/longfile.txt


$ head -n5 /tmp/longfile.txt
unavailable speedometer's garbling Zambia subcontracted fullbacks Belmont mantra's
pizzicatos carotids bitch Hernandez renovate leopard Knuth coarsen
Ramada flu occupies drippings peaces siroccos Bartók upside twiggier configurable perpetuates tapering pint paralyzed
vibraphone stoppered weirdest dispute clergy's getup perusal fork
nighties resurgence chafe

这么多好答案!

与@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
  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

(Ubuntu on Intel i5-3320M,Linux kernel 4.13,Perl 5.26)

空正则表达式

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

不可能的正则表达式

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

参考资料:

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

关于这个问题更流行的观点是:

所有涉及边界匹配器的示例都遵循相同的配方。 食谱:

  1. 取任何边界匹配器: ^ ,$,b,A,Z,z

  2. 反其道而行之

例子:

^ 和 A 用于开头,所以不要在开头使用它们

^ --> .^
\A --> .\A

B 匹配一个单词边界,因此在两者之间使用它

\b --> .\b.

$,Z 和 z 是为了结束,所以不要在结束时使用它们

$ --> $.
\Z --> \Z.
\z --> \z.

还有一些使用了“向前看”和“向后看”,它们也有相同的类比: 如果你给予积极或消极的前瞻,然后是相反的东西

(?=x)[^x]
(?!x)x

如果你跟着相反的东西后面给予正面或负面的看法

[^x](?<=x)
x(?<!x)

他们可能有更多这样的模式和更多这样的类比。

\A[^\w\W]

不管正则表达式标志如何工作。

根据 Regex101: 对于空输入字符串,0步。对于所有其他输入字符串,正好2步。

Kotlin 游乐场: https://pl.kotl.in/hdbNH73It

正如专业人士提到的,这取决于 正则表达式引擎,当然 性能基准取决于很多因素,包括设备

但是作为 ECMAScript (Java/Javascript)PCRE (PHP)表演的参考,最好的自上而下是:

  1. [] | ^[]
  2. $^(非多行标志) (快)
  3. [^\S\s] | ^[^\S\s] | ^[^\W\w] | ^[^\D\d]
  4. .^(非多行标志) (快)
  5. (?!\x00)\x00 | ^(?!\x00)\x00 | (?!\0)\0
  6. (?!a)a
  7. (?!) (慢)
  8. (?=b)a (慢)
  9. 其他例子,如 \b\B等。 (最慢)

对 Javascript 进行实时尝试 < em > (不太准确)

注意: ^ = \A(PCRE) = at Start (non-multi-line) 更多信息

^_^,它从来不匹配,并且很快失败。