web-dev-qa-db-ja.com

何にも一致しない正規表現

これはばかげた質問のように聞こえるかもしれませんが、私は仲間の開発者の何人かと長い話をしました。

そう;あなたの考えは何ですか-正規表現はどのように見えますか?

編集:なぜこれが欲しいのですか?まず、そのような表現を考えるのは面白いと思うし、スクリプトにそれが必要だからです。

そのスクリプトでは、辞書をDictionary<string, Regex>。ご覧のとおり、これには文字列と式が含まれています。

そのディクショナリに基づいて、すべてのディクショナリを作業方法の参照としてのみ使用するメソッドを作成します。そのうちの1つは、解析されたログファイルに対する正規表現と一致します。

式が一致する場合、別のDictionary<string, long>には、式によって返される値が追加されます。したがって、辞書の式と一致しないログメッセージをキャッチするために、「unknown」という新しいグループを作成しました。

このグループには、他の何とも一致しなかったすべてが追加されます。しかし、「不明な」式が(誤って)ログメッセージと一致しないようにするには、どの文字列を指定しても、絶対に一致しない式を作成する必要がありました。

したがって、あなたはこの「本当の質問ではない」理由があります...

123
F.P

これは実際には非常に簡単ですが、 実装/フラグに依存しますが*:

$a

文字列の末尾の後の文字aに一致します。幸運を。

警告:
この表現は負荷が高くなります。行全体をスキャンし、行末アンカーを検出しますが、その後はaを検出せず、負の一致を返します。 (詳細については、以下のコメントを参照してください。)


* もともと私は$も行末に一致するマルチラインモードの正規表現についてあまり考えていませんでした。実際、空の文字列改行の直前に一致するため、aのような通常の文字は$の後に表示されません。

63
Ferdinand Beyer

レバレッジ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
75
Alex Martelli

見逃したもの:

^\b$

空の文字列にはWordの境界が含まれていないため、一致しません。テスト済みPython 2.5。

37
Mark Byers

見回す:

(?=a)b

正規表現初心者の場合:前向きな見通し(?=a)は、次の文字がaであることを確認しますが、検索場所を変更しません(または、一致した文字列に「a」を含めます)。次の文字がaであることが確認されたので、正規表現の残りの部分(b)は、次の文字がbである場合にのみ一致します。したがって、この正規表現は、文字が同時にabの両方である場合にのみ一致します。

34
Amarghosh

a\bc、 どこ \bは、Wordの境界に一致する幅ゼロの式です。

Wordの途中に表示することはできません。

29
P Shved

$.

.^

$.^

(?!)

20
Knio

最大マッチング

a++a

バックトラッキングなしで、少なくとも1つのaの後に任意の数のaが続きます。次に、もう1つaと一致させてください。

または独立したサブ式

これは、a+は独立したサブ式で、その後に別のaが続きます。

(?>a+)a
11
Brad Gilbert

Perl 5.10は、(*...)シーケンスで囲まれた「動詞」と呼ばれる特別な制御ワードをサポートします。 ((?...)特殊シーケンスと比較してください。)その中には、正規表現からすぐに戻る (*FAIL) verb が含まれています。

動詞はPCREにもすぐに実装されるため、PHPまたはPCREライブラリを使用する他の言語でも使用できます。(Pythonまたはただし、Ruby。独自のエンジンを使用します。)

10
Kang Seonghoon
\B\b

\bは、単語の境界-文字と非文字の間の位置(または文字列の境界)に一致します。
\Bはその補完です-2文字間または非文字間の位置に一致します。

一緒になって、どの位置にも一致することはできません。

こちらもご覧ください:

9
Kobi

$^ または多分 (?!)

8
Bob

これはうまくいくようです:

$.
8
Jerry Fernholz

最速は:

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

「a」には特殊文字以外の文字(「x」、「y」)を使用できます。 Knioの実装はもう少し純粋かもしれませんが、この場合、「a」の代わりに選択した文字で始まらないすべての文字列の方が高速になります。これらの場合、最初の文字ではなく最初の文字の後に一致しないからです。

5
Adam Nelson

これはPythonや他の多くの言語では機能しませんが、Javascript正規表現では[]は、照合できない有効な文字クラスです。そのため、入力に関係なく、次のコードはすぐに失敗します。

var noMatch = /^[]/;

私は/$a/私にとっては、その意図を明確に伝えているからです。また、ユーザーの入力に基づいて動的にコンパイルされたパターンのフォールバックが必要なため、いつ必要になるかについても必要です。パターンが無効な場合、何にも一致しないパターンに置き換える必要があります。簡略化すると、次のようになります。

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

Pythonはそれを受け入れませんが、Perlは以下を行います:

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

最初のグループ(()s)はそれ自体に再帰するため、この正規表現は(理論的に)無限(偶数)のwsのマッチングを試みます。 Perlはuse strict; use warnings;の下でも警告を発行していないようです。そのため、少なくとも有効であり、私の(最小限の)テストは何にも一致しないため、批評のために提出します。

4
Chris Lutz

[^\d\D]または(?=a)bまたはa$aまたはa^a

4
Bart Kiers

たくさんの良い答え!

@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

(Intel i5-3320M上のUbuntu、Linuxカーネル4.13、Perl 5.26)

2
filiprem

これらの素晴らしい回答のいくつかを見た後、 @ arantiusのコメント (タイミングについて$x vs x^ vs (?!x)x)現在受け入れられている回答で、これまでに与えられたソリューションの。

@arantiusの275k行標準を使用して、Python(v3.5.2、IPython 6.2.1)で次のテストを実行しました。

TL; DR:'x^'および'x\by'は、少なくとも〜16の係数で最速であり、@ arantiusの発見に反して、(?!x)xslowest(〜37倍遅い)。したがって、速度の問題は確かに実装に依存します。速度が重要な場合は、コミットする前に目的のシステムで自分でテストしてください。

UPDATE:明らかに'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)

これを初めて実行したとき、最後の3つの式をrawするのを忘れていたため、'\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
2
nivk

空の正規表現

何にも一致しない最適な正規表現は、空の正規表現です。しかし、すべての正規表現エンジンがそれを受け入れるかどうかはわかりません。

不可能な正規表現

他の解決策は、不可能な正規表現を作成することです。見つけた $-^は、テキストのサイズに関係なく、計算に2ステップしかかかりません( https://regex101.com/r/yjcs1Z/1 )。

参考のために:

  • $^および$.計算に36ステップかかる-> O(1)
  • \b\Bは私のサンプルで1507ステップを取り、文字列の文字数とともに増加します-> O(n)

この質問に関するより一般的なスレッド:

2
aeon

私は信じている

\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)が何であれ、障害発生までの時間は一定であると信じています(ただし、ベンチマークは行っていません)。

2
tzot

境界マッチャーを含むすべての例は、同じレシピに従います。レシピ:

  1. 境界マッチャーのいずれかを取る:^、$、\ b、\ A、\ Z、\ z

  2. 彼らが意図されていることとは反対に

例:

^および\ Aは最初のものであるため、最初に使用しないでください

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

\ bはWordの境界に一致するため、その間に使用します

\b --> .\b.

$、\ Z、および\ zは最後のものであるため、最後に使用しないでください

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

その他には、先読みと後読みの使用が含まれますが、これらも同じアナロジーで動作します:正または負の先読みを行い、その後に反対の何かが続く場合

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

あなたが正反対の何かの後ろに正または負の後読みを与えた場合

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

それらはより多くのそのようなパターンであり、より多くのそのような類推である可能性があります。

2
Arun
(*FAIL)

または

(*F)

PCREとPerlを使用すると、このバックトラック制御動詞を使用して、パターンを即座に失敗させることができます。

たぶんこれ?

/$.+^/
1
Dan Breen
'[^0-9a-zA-Z...]*'

...をすべての印刷可能な記号に置き換えます;)。これはテキストファイル用です。

0
Drakosha

正規表現の代わりに、常にfalseのifステートメントを使用するのはどうですか? javascriptの場合:

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