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

这可能听起来像一个愚蠢的问题,但我与我的一些开发人员长谈,听起来像是一个有趣的事情想起来。

所以; 你的想法是什么 – 一个正则expression式是什么样的,永远不会被任何string匹配!

编辑 :为什么我要这个? 那么,首先是因为我觉得有意思的是想到这样一个expression,其次是因为我需要一个脚本。

在该脚本中,我将字典定义为Dictionary<string, Regex> 。 如你所见,它包含一个string和一个expression式。

基于这个字典,我创build了一些方法,这些方法全部使用这个字典作为他们应该如何工作的参考,其中一个方法将正则expression式与parsing的日志文件进行匹配。

如果expression式匹配,则另一个Dictionary<string, long>被添加expression式返回的值。 因此,为了捕获任何不符合字典中的expression式的日志消息,我创build了一个名为“unknown”的新组。

对这个组别来说,所有与其他东西不匹配的东西都会被添加 但为了防止“未知”expression错误(偶然)一个日志消息,我不得不创build一个绝对不匹配的expression式,不pipe我给它什么string。

因此,你有我的理由这个“不是一个真正的问题”…

这实际上很简单, 虽然它取决于执行/标志 *:

 $a 

在string结尾后会匹配一个字符a 。 祝你好运。

警告:
这个expression式是很昂贵的 – 它会扫描整行,find行结束符,然后才finda并返回一个负值匹配。 (有关更多详细信息,请参阅以下注释。


*原来我没有多思考多行模式正则expression式,其中$也匹配行的末尾。 实际上,它会匹配换行符之前的空string,所以像$这样的普通字符永远不会出现在$之后。

利用negative lookahead

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

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

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

 \A(?!x)x 

环视四周:

(?=a)b

对于正则expression式新手:正面看(?=a)确保下一个字符是a ,但不会更改search位置(或在匹配的string中包含“a”)。 现在下一个字符被确认为a ,正则expression式( b )的剩余部分只有在下一个字符是b时才匹配。 因此,只有当一个字符同时ab时,这个正则expression式才匹配。

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

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

$.

.^

$.^

(?!)

一个错过了:

 ^\b$ 

它不能匹配,因为空string不包含字边界。 在Python 2.5中testing

最大匹配

 a++a 

至less有一个a后面跟着任意数量的a ,没有回溯。 然后尝试再匹配一个。

或独立的子expression式

这相当于将a+放在一个独立的子expression式中,接着是另一个。

 (?>a+)a 

这似乎工作:

 $. 

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

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

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

 \B\b 

\b匹配单词边界 – 字母和非字母(或string边界)之间的位置。
\B是它的补充 – 它匹配两个字母之间或非字母之间的位置。

他们在一起不能匹配任何位置。

也可以看看:

  • 单词边界
  • 这种模式不匹配几个位置
  • 灵感

最快的将是:

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

'a'可以是任何非特殊字符('x','y')。 Knio的实现可能会更纯一些,但是对于所有不以任何字符开头而不是以“a”开始的string,这个string会更快,因为在第一个字符之后它不匹配,而不是在第二个字符之后匹配。

Python不会接受它,但Perl会:

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

这个正则expression式应该(理论上)试图匹配一个无限(甚至)数量的w ,因为第一个组(s)recursion到自身中。 Perl似乎并没有发出任何警告,即使在use strict; use warnings;情况下也是如此use strict; use warnings; use strict; use warnings; ,所以我认为这至less是有效的,我的(最小的)testing不能匹配任何东西,所以我把它提交给你的批评。

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

这不适用于Python和许多其他语言,但在Javascript正则expression式中, []是无法匹配的有效字符类。 所以不pipeinput如何,以下都会立即失败:

 var noMatch = /^[]/; 

我比/$a/更喜欢它,因为对我来说,它清楚地expression了它的意图。 至于什么时候需要它,我需要它,因为我需要一个基于用户input的dynamic编译模式的后备。 当模式无效时,我需要用一个什么都不匹配的模式replace它。 简化,看起来像这样:

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

也许这个?

 /$.+^/ 

我相信

 \Z RE FAILS! \A 

甚至包括正则expression式包含诸如MULTILINE,DOTALL等标志的情况

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

我相信(但我没有对它进行基准testing),无论\Z\A之间的string的长度(> 0)如何,失败的时间应该是不变的。

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

并用所有可打印的符号replace…)。 这是一个文本文件。

怎么样,而不是正则expression式,只是使用一个总是假的if语句? 在javascript中:

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

要么

 (*F) 

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

在看到这些好的答案之后, @ arantius的评论 (关于时间$x vs x^ vs (?!x)x )在目前被接受的答案上让我想要一些迄今为止给出的解决scheme。

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

TL; DR: 'x^''x\by'是最快的至less16倍,与@ arantius的发现相反, (?!x)x ?! (?!x)x最慢的 (约37倍)。 所以速度问题肯定是依赖于实现的。 如果速度对你来说很重要的话,你可以在你想要的系统上自己testing一下。

更新:时间'x^''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) 

第一次运行这个时,我忘记了最后3个expression式,所以'\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 

我的testing文件是使用“…可读内容和无重复行” (在Ubuntu 16.04上)的公式创build的:

 $ 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 

一个不依赖regexp实现的可移植解决scheme就是使用一个你肯定永远不会出现在日志消息中的常量string。 例如根据以下内容创build一个string:

 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()) 

创build一个只包含字母数字和' - '的模式(其中没有一个是正则expression式的特殊字符),但统计上不可能在同一个string出现之前(因为这是一个GUID的全部点)。