これはばかげた質問のように聞こえるかもしれませんが、私は仲間の開発者の何人かと長い話をしました。
そう;あなたの考えは何ですか-正規表現はどのように見えますか?
編集:なぜこれが欲しいのですか?まず、そのような表現を考えるのは面白いと思うし、スクリプトにそれが必要だからです。
そのスクリプトでは、辞書をDictionary<string, Regex>
。ご覧のとおり、これには文字列と式が含まれています。
そのディクショナリに基づいて、すべてのディクショナリを作業方法の参照としてのみ使用するメソッドを作成します。そのうちの1つは、解析されたログファイルに対する正規表現と一致します。
式が一致する場合、別のDictionary<string, long>
には、式によって返される値が追加されます。したがって、辞書の式と一致しないログメッセージをキャッチするために、「unknown」という新しいグループを作成しました。
このグループには、他の何とも一致しなかったすべてが追加されます。しかし、「不明な」式が(誤って)ログメッセージと一致しないようにするには、どの文字列を指定しても、絶対に一致しない式を作成する必要がありました。
したがって、あなたはこの「本当の質問ではない」理由があります...
これは実際には非常に簡単ですが、 実装/フラグに依存しますが*:
$a
文字列の末尾の後の文字a
に一致します。幸運を。
警告:
この表現は負荷が高くなります。行全体をスキャンし、行末アンカーを検出しますが、その後はa
を検出せず、負の一致を返します。 (詳細については、以下のコメントを参照してください。)
* もともと私は$
も行末に一致するマルチラインモードの正規表現についてあまり考えていませんでした。実際、空の文字列改行の直前に一致するため、a
のような通常の文字は$
の後に表示されません。
レバレッジ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
見逃したもの:
^\b$
空の文字列にはWordの境界が含まれていないため、一致しません。テスト済みPython 2.5。
見回す:
(?=a)b
正規表現初心者の場合:前向きな見通し(?=a)
は、次の文字がa
であることを確認しますが、検索場所を変更しません(または、一致した文字列に「a」を含めます)。次の文字がa
であることが確認されたので、正規表現の残りの部分(b
)は、次の文字がb
である場合にのみ一致します。したがって、この正規表現は、文字が同時にa
とb
の両方である場合にのみ一致します。
a\bc
、 どこ \b
は、Wordの境界に一致する幅ゼロの式です。
Wordの途中に表示することはできません。
$.
.^
$.^
(?!)
a++a
バックトラッキングなしで、少なくとも1つのa
の後に任意の数のa
が続きます。次に、もう1つa
と一致させてください。
これは、a+
は独立したサブ式で、その後に別のa
が続きます。
(?>a+)a
Perl 5.10は、(*...)
シーケンスで囲まれた「動詞」と呼ばれる特別な制御ワードをサポートします。 ((?...)
特殊シーケンスと比較してください。)その中には、正規表現からすぐに戻る (*FAIL)
verb が含まれています。
動詞はPCREにもすぐに実装されるため、PHPまたはPCREライブラリを使用する他の言語でも使用できます。(Pythonまたはただし、Ruby。独自のエンジンを使用します。)
\B\b
\b
は、単語の境界-文字と非文字の間の位置(または文字列の境界)に一致します。\B
はその補完です-2文字間または非文字間の位置に一致します。
一緒になって、どの位置にも一致することはできません。
こちらもご覧ください:
$^
または多分 (?!)
?
これはうまくいくようです:
$.
最速は:
r = re.compile(r'a^')
r.match('whatever')
「a」には特殊文字以外の文字(「x」、「y」)を使用できます。 Knioの実装はもう少し純粋かもしれませんが、この場合、「a」の代わりに選択した文字で始まらないすべての文字列の方が高速になります。これらの場合、最初の文字ではなく最初の文字の後に一致しないからです。
これはPythonや他の多くの言語では機能しませんが、Javascript正規表現では[]
は、照合できない有効な文字クラスです。そのため、入力に関係なく、次のコードはすぐに失敗します。
var noMatch = /^[]/;
私は/$a/
私にとっては、その意図を明確に伝えているからです。また、ユーザーの入力に基づいて動的にコンパイルされたパターンのフォールバックが必要なため、いつ必要になるかについても必要です。パターンが無効な場合、何にも一致しないパターンに置き換える必要があります。簡略化すると、次のようになります。
try {
var matchPattern = new RegExp(someUserInput);
}
catch (e) {
matchPattern = noMatch;
}
Pythonはそれを受け入れませんが、Perlは以下を行います:
Perl -ne 'print if /(w\1w)/'
最初のグループ(()
s)はそれ自体に再帰するため、この正規表現は(理論的に)無限(偶数)のw
sのマッチングを試みます。 Perlはuse strict; use warnings;
の下でも警告を発行していないようです。そのため、少なくとも有効であり、私の(最小限の)テストは何にも一致しないため、批評のために提出します。
[^\d\D]
または(?=a)b
またはa$a
またはa^a
たくさんの良い答え!
@nivkの答えと同様に、決して一致しない正規表現のさまざまなバリエーションについて、Perlのパフォーマンス比較を共有したいと思います。
正規表現速度:
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
正規表現速度:
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)
これらの素晴らしい回答のいくつかを見た後、 @ 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)x
はslowest(〜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つの式をr
awするのを忘れていたため、'\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ステップしかかかりません( https://regex101.com/r/yjcs1Z/1 )。
$^
および$.
計算に36ステップかかる-> O(1)\b\B
は私のサンプルで1507ステップを取り、文字列の文字数とともに増加します-> O(n)私は信じている
\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)が何であれ、障害発生までの時間は一定であると信じています(ただし、ベンチマークは行っていません)。
境界マッチャーを含むすべての例は、同じレシピに従います。レシピ:
境界マッチャーのいずれかを取る:^、$、\ b、\ A、\ Z、\ z
彼らが意図されていることとは反対に
例:
^および\ Aは最初のものであるため、最初に使用しないでください
^ --> .^
\A --> .\A
\ bはWordの境界に一致するため、その間に使用します
\b --> .\b.
$、\ Z、および\ zは最後のものであるため、最後に使用しないでください
$ --> $.
\Z --> \Z.
\z --> \z.
その他には、先読みと後読みの使用が含まれますが、これらも同じアナロジーで動作します:正または負の先読みを行い、その後に反対の何かが続く場合
(?=x)[^x]
(?!x)x
あなたが正反対の何かの後ろに正または負の後読みを与えた場合
[^x](?<=x)
x(?<!x)
それらはより多くのそのようなパターンであり、より多くのそのような類推である可能性があります。
(*FAIL)
または
(*F)
PCREとPerlを使用すると、このバックトラック制御動詞を使用して、パターンを即座に失敗させることができます。
たぶんこれ?
/$.+^/
'[^0-9a-zA-Z...]*'
...をすべての印刷可能な記号に置き換えます;)。これはテキストファイル用です。
正規表現の代わりに、常にfalseのifステートメントを使用するのはどうですか? javascriptの場合:
var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}