Regex Golfのヒント


43

言語固有のゴルフのヒントのスレッドと同様に、正規表現を短縮する一般的なトリックは何ですか?

ゴルフに関しては、正規表現の3つの使用法を見ることができます。古典的な正規表現ゴルフ(「一致するリストと失敗するリスト」)、正規表現を使用して計算問題と正規表現を解決するより大きなゴルフコード。これらのいずれかまたはすべてに対処するためのヒントを投稿してください。ヒントが1つ以上のフレーバーに限定されている場合は、これらのフレーバーを上部に記載してください。

いつものように、回答ごとに1つのヒント(または非常に密接に関連するヒントのファミリー)に固執してください。そうすることで、最も有用なヒントが投票でトップに上がります。


フラッグラントセルフプロモーション:これは正規表現のどのカテゴリに該当しますか?codegolf.stackexchange.com/a/37685/8048
カイルストランド

@KyleStrand「より大きなゴルフ用コードの一部として使用される正規表現」。
マーティンエンダー

回答:


24

逃げないとき

これらの規則は、すべてではないにしても、ほとんどのフレーバーに適用されます。

  • ] 一致しない場合はエスケープする必要はありません。

  • {そして}、彼らは繰り返しの一部ではないときなどは、エスケープする必要はありません{a}一致して{a}、文字通り。のようなものと一致させたい場合でも{2}、それらのうちの1つだけをエスケープする必要があります{2\}

文字クラスの場合:

  • ]それは例えば、文字セットの最初の文字だ時にエスケープを必要としない[]abc]のいずれかと一致する]abc、またはそれが後の第二文字だとき^、例えば[^]]何が、と一致しました]。(注目すべき例外:ECMAScriptフレーバー!)

  • [エスケープする必要はまったくありません。上記のヒントと合わせて、これは両方の括弧を恐ろしく反直感的な文字クラスと一致させることができることを意味します[][]

  • ^文字セットの最初の文字でない場合、エスケープする必要はありません[ab^c]

  • -、またはなどの^文字セットの最初の文字(の後の2番目)または最後の文字の場合、エスケープする必要はありません。[-abc][^-abc][abc-]

  • 文字クラス外のメタ文字であっても、文字クラス内で他の文字をエスケープする必要はありません(バックスラッシュ\自体を除く)。

また、一部のフレーバー^$は、それぞれ正規表現の先頭または末尾にない場合に文字通り一致します。

(いくつかの詳細を記入してくれた@MartinBüttnerに感謝します)


実際のドットをエスケープする必要のない文字クラスで囲むことで、実際のドットをエスケープすることを好む人もいます(例:)[.]。それは、通常、この場合には1つのバイトを救う脱出\.
CSᵠ

[Javaでエスケープする必要があることに注意してください。ただし、ICU(AndroidおよびiOSで使用)または.NETについてはわかりません。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

18

ASCIIテーブル内のすべての印刷可能文字に一致する単純な正規表現。

[ -~]

1
純粋な素晴らしさ、標準のUSキーボードからのすべての文字!注:(拡張範囲127から255を含まない標準のASCIIテーブル
CSᵠ

よく使用しますが、一般的な「通常の」文字TABがありません。また、LC_ALL = "C"(または同様の)を使用していることを前提としています。他のロケールは失敗します。
オリビエデュラック

そのようにハイフンを使用して、ASCIIテーブル内の任意の範囲の文字を指定できますか?それは正規表現のすべてのフレーバーで機能しますか?
ジョシュウィジー

14

正規表現のフレーバーを知る

正規表現は本質的に言語に依存しないと考える人は驚くほど多くいます。ただし、実際にはフレーバーにはかなり大きな違いがあります。特にコードゴルフでは、それらのいくつかとそれらの興味深い機能を知っておくとよいので、各タスクに最適なものを選ぶことができます。以下に、いくつかの重要なフレーバーの概要と、他のフレーバーとの違いを示します。(このリストは完全に完成することはできませんが、本当に眩しい何かを見逃したかどうか教えてください。)

PerlおよびPCRE

Perlのフレーバーにあまり慣れておらず、ほとんど同等であるため、これらを1つのポットに入れています(PCREは結局Perl互換の正規表現用です)。Perlフレーバーの主な利点は、正規表現と置換の内部から実際にPerlコードを呼び出すことができることです。

  • 再帰/サブルーチン。おそらくゴルフの最も重要な機能(いくつかのフレーバーにのみ存在します)。
  • 条件付きパターン(?(group)yes|no)
  • 支持体は、との置換文字列にケースの変更\l\u\L\U
  • PCREは、各代替が異なる(ただし固定された)長さを持つことができる後読みの交互を可能にします。(Perlを含むほとんどのフレーバーでは、ルックビハインドに全体的な固定長が必要です。)
  • \G 一致を前の一致の最後に固定します。
  • \K 試合の始まりをリセットする
  • PCREは、Unicode文字のプロパティとスクリプトの両方をサポートしています
  • \Q...\Eキャラクターの長い実行をエスケープする。多くのメタ文字を含む文字列を一致させようとする場合に便利です。

。ネット

これはおそらく最も強力なフレーバーであり、欠点はごくわずかです。

ゴルフに関する重要な欠点の1つは、他のいくつかのフレーバーのような所有量指定子をサポートしていないことです。代わり.?+に書く必要があります(?>.?)

Java

ルビー

最近のバージョンでは、このフレーバーは、サブルーチン呼び出しのサポートを含め、PCREと同様に強力です。Javaと同様に、文字クラスの結合と交差もサポートします。特別な機能の1つは、16進数の組み込み文字クラス\h(および否定\H)です。

しかし、ゴルフに最も役立つ機能は、Rubyが数量詞を処理する方法です。最も注目すべきは、括弧なしで量指定子をネストできることです。.{5,7}+機能し.{3}?ます。また、他のほとんどのフレーバーとは異なり、数量詞の下限0が省略可能な場合、たとえば.{,5}と同等.{0,5}です。

サブルーチンに関しては、PCREのサブルーチンとRubyのサブルーチンの主な違いは、Rubyの構文が1バイト長い(?n)vsこと\g<n>ですが、Rubyのサブルーチンをキャプチャに使用できるのに対し、PCREはサブルーチンの終了後にキャプチャをリセットします。

最後に、行に関連する修飾子については、他のほとんどのフレーバーとは異なるセマンティクスがあります。通常m、他のフレーバーで呼び出される修飾子は、Rubyでは常にオンになっています。したがって、文字列の先頭と末尾だけでなく^$常に行の先頭と末尾に一致します。あなたはこの動作を必要とする場合、これはあなたにバイトを保存することができますが、そうでない場合は、交換する必要がありますので、それは、あなたに余分なバイトの費用がかかります^し、$\A\z、それぞれ。それに加えて、通常呼び出されるs.一致する改行を行う)修飾子は、m代わりにRuby で呼び出されます。これはバイトカウントには影響しませんが、混乱を避けるために留意する必要があります。

Python

Pythonには確かなフレーバーがありますが、私はあなたが他のどこにも見つけられないような特に便利な機能を知りません。

ただし、ある時点でモジュールを置き換えることを目的とした代替フレーバーがありre、多くの興味深い機能が含まれています。再帰、可変長の後読み、および文字クラスの組み合わせ演算子のサポートを追加することに加えて、ファジーマッチングという独自の機能も備えています。基本的に、許可されるエラー(挿入、削除、置換)の数を指定できます。また、エンジンはおおよその一致を提供します。

ECMAScript

ECMAScriptのフレーバーは非常に限られているため、ゴルフにはあまり役立ちません。唯一の目的は、空の文字クラス [^]否定することで、任意の文字と一致すること、および無条件に失敗する空の文字クラス[](通常とは対照的に(?!))です。残念ながら、このフレーバーには、通常の問題で後者を有効にする機能がありません。

ルア

Luaには独自のかなりユニークなフレーバーがあり、これはかなり制限されています(たとえば、グループを定量化することさえできません)が、便利で興味深い機能がいくつかあります。

  • 組み込みの文字クラスには、句読点、大文字/小文字、16進数を含む多数の略記があります。
  • これにより%b、バランスの取れた文字列に一致する非常にコンパクトな構文がサポートされます。たとえば%b()、aに一致し(、次に一致するものまですべて一致します)(内部で一致したペアを正しくスキップします)。ここでは任意の2文字(を使用)できます。

ブースト

Boostの正規表現は本質的にPerlのものです。ただし、大文字と小文字の変更や条件など、正規表現の置換のための優れた新機能がいくつかあります。私の知る限り、後者はBoostに固有のものです。


後読みの先読みは、後読みの境界制限を突き抜けることに注意してください。JavaとPCREでテスト済み。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

.?+同等ではありません.*か?
CalculatorFeline

@CalculatorFeline前者は所有的0-or-1量指定子(所有的量指定子をサポートするフレーバー)であり、後者は0-以上の量指定子です。
マーティンエンダー

@CalculatorFeline ah混乱を理解しています。タイプミスがありました。
マーティンエンダー

13

キャラクタークラスを知る

ほとんどの正規表現フレーバーには、事前定義された文字クラスがあります。たとえば\d、10進数の数字と一致します[0-9]。これは、よりも3バイト短くなります。はい、\d一部のフレーバーでもUnicode数字と一致する可能性があるため、わずかに異なる場合がありますが、ほとんどの課題ではこれは違いをもたらしません。

ほとんどの正規表現フレーバーで見られるいくつかの文字クラスは次のとおりです。

\d      Match a decimal digit character
\s      Match a whitespace character
\w      Match a word character (typically [a-zA-Z0-9_])

さらに、次のものもあります。

\D \S \W

上記の否定バージョンです。

追加の文字クラスがあるかどうか、フレーバーを確認してください。たとえば、PCREに\Rは改行があり、Luaには小文字や大文字などのクラスもあります。

(これらを指摘してくれた@HamZaと@MartinBüttnerに感謝します)


3
\RPCREの改行用。
ハムザ

12

キャプチャしていないグループを気にしないでください(...)

このヒントは、(少なくとも)人気のあるPerl風のすべてのフレーバーに適用されます。

これは明らかかもしれませんが、(ゴルフではない場合)(?:...)可能な限り、非キャプチャグループを使用することをお勧めします。?:ただし、これらの2つの余分なキャラクターは、ゴルフをするときに無駄です。したがって、後方参照するつもりがない場合でも、キャプチャグループを使用してください。

ただし、1つ(まれな)例外があります。グループ10を少なくとも3回逆参照する場合、以前のグループを非キャプチャグループに変更することで、すべてのバイトが\10sになるように、実際にバイトを節約できます\9。(グループ11を少なくとも5回使用する場合など、同様のトリックが適用されます。)


10が3を必要とするのに、11が5倍の価値があるのはなぜですか?
ニックハートリー

1
@QPaysTaxesが1バイトを保存する$9代わりに、$10または$11一度使用すると、1バイト節約できます。回す$10には、$9いずれかが必要です。?:次の3つが必要ですので、2バイトで、$10何かを保存するのを。回す$11には$92が必要です?:あなたが5必要がありますので、4バイトであるのを$11、何かを保存するために、Sを(または5 $10$11組み合わせました)。
マーティンエンダー

10

パターンの再利用のための再帰

少数のフレーバーが再帰をサポートしています(私の知る限り、Perl、PCRE、およびRuby)。再帰的な問題を解決しようとしていない場合でも、この機能により、より複雑なパターンで大量のバイトを節約できます。そのグループ自体の内部で別の(名前付きまたは番号付き)グループを呼び出す必要はありません。正規表現に複数回出現する特定のパターンがある場合は、それをグループ化し、そのグループ外でそれを参照します。これは、通常のプログラミング言語でのサブルーチン呼び出しと違いはありません。代わりに

...someComplexPatternHere...someComplexPatternHere...someComplexPatternHere... 

Perl / PCREでは次のことができます。

...(someComplexPatternHere)...(?1)...(?1)...

またはRubyの場合:

...(someComplexPatternHere)...\g<1>...\g<1>...

それが最初のグループである場合(もちろん、再帰呼び出しで任意の番号を使用できます)。

これは、後方参照()と同じではないことに注意してください\1。後方参照は、グループが前回一致したものとまったく同じ文字列と一致します。これらのサブルーチン呼び出しは、実際にパターンを再度評価します。someComplexPatternHere長い文字クラスを取得する例として:

a[0_B!$]b[0_B!$]c[0_B!$]d

これは次のようなものに一致します

aBb0c!d

動作を保持している間は、ここで後方参照を使用できないことに注意してください。Band 0!は同じではないため、上記の文字列では後方参照が失敗します。ただし、サブルーチン呼び出しでは、パターンは実際に再評価されます。上記のパターンは完全に同等です

a([0_B!$])b(?1)c(?1)d

サブルーチン呼び出しでのキャプチャ

PerlとPCREに関する注意点の1つ:1上記の例のグループにさらにグループが含まれている場合、サブルーチン呼び出しはそれらのキャプチャを記憶しません。この例を考えてみましょう:

(\w(\d):)\2 (?1)\2 (?1)\2

これは一致しません

x1:1 y2:2 z3:3

サブルーチン呼び出しが戻ると、グループの新しいキャプチャ2が破棄されるためです。代わりに、このパターンは次の文字列に一致します。

x1:1 y2:1 z3:1

これはサブルーチン呼び出しキャプチャを保持するRubyとは異なるため、同等のRuby正規表現(\w(\d):)\2 \g<1>\2 \g<1>\2は上記の最初の例に一致します。


\1Javascriptに使用できます。そして、PHPもそうです(私は推測します)。
イスマエルミゲル

5
@IsmaelMiguelこれは後方参照ではありません。これにより、実際にパターンが再度評価されます。たとえば、(..)\1一致するababが失敗するのabbaに対し(..)(?1)、後者は一致します。実際には、前回一致したものと文字通り一致するのではなく、式が再び適用されるという意味でのサブルーチン呼び出しです。
マーティンエンダー

うわー、私にはわからなかった!毎日何か新しいことを学ぶ
イスマエルミゲル

.NET(またはこの機能のない他のフレーバー):(?=a.b.c)(.[0_B!$]){3}d
jimmy23013

@ user23013は、この特定の例に非常に固有のようです。さまざまなルックアラウンドで特定のサブパターンを再利用する場合、それが適用可能かどうかはわかりません。
マーティンエンダー

9

マッチを失敗させる

正規表現を使用して計算問題を解決したり、非常に非正規の言語に一致させたりする場合、文字列のどこにいてもパターンの分岐を失敗させることが必要な場合があります。単純なアプローチは、空の負の先読みを使用することです。

(?!)

内容(空のパターン)は常に一致するため、負の先読みは常に失敗します。しかし、多くの場合、はるかに単純なオプションがあります。入力に表示されないことがわかっている文字を使用するだけです。たとえば、入力が常に数字のみで構成されることがわかっている場合は、単に使用できます

!

または、失敗を引き起こす他の非数字、非メタ文字。

入力に潜在的にサブストリングが含まれる可能性がある場合でも、より短い方法があり(?!)ます。アンカーを最後ではなくパターン内に表示できるフレーバーでは、次の2文字のソリューションのいずれかを使用できます。

a^
$a

ただし、一部のフレーバーは、これらの位置でリテラル文字として扱われ^$実際にはアンカーとして意味をなさないため、注意してください。

ECMAScriptフレーバーには、かなりエレガントな2文字のソリューションもあります

[]

これは空の文字クラスであり、次の文字がクラス内の文字の1つであることを確認しようとしますが、クラス内に文字がないため、常に失敗します。文字クラスは通常空にできないため、これは他のフレーバーでは機能しないことに注意してください。


8

あなたの最適化OR

RegExに3つ以上の選択肢がある場合:

/aliceblue|antiquewhite|aquamarine|azure/

一般的な開始があるかどうかを確認します。

/a(liceblue|ntiquewhite|quamarine|zure)/

そして、たぶん共通の結末ですか?

/a(liceblu|ntiquewhit|quamarin|zur)e/

注:3は開始点であり、同じ長さを占め、4 +は違いを生みます


しかし、それらのすべてに共通の接頭辞がない場合はどうでしょうか?(明確にするために空白のみが追加されています)

/aliceblue|antiquewhite|aqua|aquamarine|azure
|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood
|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan/

3+ルールが意味をなす限り、それらをグループ化します。

/a(liceblue|ntiquewhite|qua|quamarine|zure)
|b(eige|isque|lack|lanchedalmond|lue|lueviolet|rown|urlywood)
|c(adetblue|hartreuse|hocolate|oral|ornflowerblue|ornsilk|rimson|yan)/

または、エントロピーがユースケースを満たす場合でも一般化します。

/\w(liceblue|ntiquewhite|qua|quamarine|zure
|eige|isque|lack|lanchedalmond|lue|lueviolet|rown|urlywood
|adetblue|hartreuse|hocolate|oral|ornflowerblue|ornsilk|rimson|yan)/

^この場合には、我々は確信している私たちはいずれかを得ることはありませんcluecrown slack Ryan

この「いくつかのテストによる」も、最初からアンカーを提供するため、パフォーマンスが向上します。


1
共通の開始または終了が1文字より長い場合、2つをグループ化しても違いが生じる可能性があります。aqua|aquamarineaqua(|marine)またはが好きaqua(marine)?です。
パエロエベルマン

6

これはかなり簡単ですが、述べる価値があります。

文字クラス[a-zA-Z]を繰り返すことに気付いた場合は、おそらく(case- i nsensitive修飾子)を使用して正規表現に[a-z]追加できます。i

たとえば、Rubyでは、次の2つの正規表現は同等です。

/[a-zA-Z]+\d{3}[a-zA-Z]+/
/[a-z]+\d{3}[a-z]/i -7バイト短縮

さらに言えば、他の修飾子は全体の長さを短くすることもできます。これを行う代わりに:

/(.|\n)/

これは(ドットは改行と一致しないため)任意の文字に一致し、使用のSイングルラインモディファイsドットマッチ改行を行い、。

/./s -3バイト短縮


Rubyには、正規表現用の組み込み文字クラスがたくさんあります。参照このページをし、「文字のプロパティ」を検索してください。
すばらしい例は「通貨記号」です。ウィキペディアによると、可能な通貨記号が大量にあり、それらを文字クラスに入れると非常に高価([$฿¢₡Ð₫€.....])になりますが、6バイトで一致させることができます。\p{Sc}


1
JavaScriptを除き、s修飾子はサポートされていません。:(ただし、JavaScriptの独自の/[^]/トリックを使用できます
。– manatwork

多くの場合(.|\n).他のタイプの行区切り文字とも一致しないため、一部のフレーバーでも機能しないことに注意してください。ただし、これを行う通常の方法(なしs[\s\S]は、と同じバイト(.|\n)です。
マーティンエンダー

@MartinBüttner、私のアイデアは、関連するヒントを終了する他の行と一緒に保管することでした。ただし、この答えが修飾子に関するものであると感じた場合、再投稿しても異論はありません。
マナトワーク

@manatwork完了(および関連する非ES固有のトリックも追加)
マーティンエンダー

6

シンプルな言語パーサー

REのような非常にシンプルなパーサーを構築でき\d+|\w+|".*?"|\n|\Sます。一致する必要があるトークンは、RE「または」文字で区切られます。

REエンジンは、テキストの現在の位置で一致を試みるたびに、最初のパターン、2番目のパターンなどを試行します。失敗した場合(たとえば、スペース文字で)、先に進み、一致を再試行します。順序が重要です。\S用語の前に\d+用語を配置する\Sと、パーサーが破損するスペース以外の文字で最初に一致します。

".*?"我々は一度に1つの文字列に一致するように文字列マッチャは、非欲張り修飾子を使用しています。REに貪欲でない関数がない場合"[^"]*"は、同等の関数を使用できます 。

Pythonの例:

text = 'd="dogfinder"\nx=sum(ord(c)*872 for c in "fish"+d[3:])'
pat = r'\d+|\w+|".*?"|\n|\S'
print re.findall(pat, text)

['d', '=', '"dogfinder"', '\n', 'x', '=', 'sum', '(', 'ord', '(', 'c', ')',
    '*', '872', 'for', 'c', 'in', '"fish"', '+', 'd', '[', '3', ':', ']', ')']

ゴルフのPythonの例:

# assume we have language text in A, and a token processing function P
map(P,findall(r'\d+|\w+|".*?"|\n|\S',A))

一致する必要がある言語のパターンとその順序を調整できます。この手法は、JSON、基本的なHTML、および数値式に適しています。Python 2で何度も使用されていますが、他の環境で動作するのに十分な汎用性が必要です。


6

\K 後読みの代わりに

PCREとPerl \Kは、一致の始まりをリセットするエスケープシーケンスをサポートしています。つまりab\Kcd、入力文字列を含める必要がありますabcdが、報告される一致はのみですcd

パターンの先頭(おそらく最も可能性の高い場所)で肯定的な後読みを使用している場合、ほとんどの場合、\K代わりに使用して3バイトを節約できます。

(?<=abc)def
abc\Kdef

これはほとんどの目的で同等ですが、完全ではありません。違いは、長所と短所の両方をもたらします。

  • 利点:PCREとPerlは、任意の長さの後読みをサポートしていません(.NETのみがサポートしています)。つまり、次のようなことはできません(?<=ab*)。しかし、\Kあなたはその前にどんな種類のパターンでも置くことができます!だから、ab*\K動作します。これにより、実際に適用可能な場合に、この手法が非常に強力になります。
  • 利点:ルックアラウンドは後戻りしません。これは、後で後方参照するために後読みで何かをキャプチャしたい場合に関連しますが、有効な一致につながる可能性のあるキャプチャがいくつかあります。この場合、正規表現エンジンはこれらの可能性の1つだけを試します。\K正規表現のその部分を使用すると、他のすべてのようにバックトラックされます。
  • 欠点:おそらくご存知のとおり、正規表現のいくつかの一致は重複できません。先読みは、以前の一致ですでに消費された文字列の一部を検証できるため、多くの場合、この制限を部分的に回避するためにルックアラウンドが使用されます。したがって、後に続く すべての文字に一致させたいab場合は、を使用できます(?<=ab).。与えられた入力

    ababc
    

    これは2番目aとに一致しcます。これで再現できません\K。を使用した場合ab\K.、最初の一致のみが取得されることになりますab。これは、現在はルックアラウンドではないためです。


パターンが\K肯定アサーション内でエスケープシーケンスを使用する場合、成功した一致の報告された開始は、一致の終了よりも大きくなる可能性があります。
hwnd

@hwnd私のポイントは、与えられたababc、2番目acwithの両方を一致させる方法がないということ\Kです。一致するのは1つだけです。
マーティンエンダー

機能自体ではなく、あなたは正しいです。アンカーする必要があります\G
hwnd

@hwndああ、今あなたの主張がわかります。しかし、私はその時点で(ゴルフの観点から)ネガティブなルックビハインドを使った方が良いと思います。なぜなら、.最後の試合の試合が実際にであったかどうかわからないからですa
マーティンエンダー

1
\ K =)の興味深い使用
hwnd

5

任意の文字に一致

ECMAScriptフレーバーには、すべての文字(改行を含む)に一致するs修飾子があり.ません。これは、完全に任意の文字を照合するための単一文字のソリューションがないことを意味します。他のフレーバーの標準ソリューション(s何らかの理由で使用したくない場合)は[\s\S]です。ただし、ECMAScriptは空の文字クラスをサポートする唯一のフレーバーです(私の知る限り)[^]。したがって、はるかに短い代替手段があります。これは否定された空の文字クラスです。つまり、どの文字にも一致します。

他のフレーバーでも、このテクニックから学ぶことができます:使用したくない場合s.他の場所での通常の意味が必要な場合など)、改行文字と印刷可能文字の両方を一致させる短い方法があります。入力に表示されないことがわかっている文字がある場合。たとえば、改行で区切られた数字を処理しています。その後、文字列の一部ではない[^!]こと!がわかっているため、任意の文字をと一致させることができます。これにより、ナイーブ[\s\S]またはで2バイト節約できます[\d\n]


4
Perlでは、モードの影響を受けないことを除いて、モード外での\N意味を正確に.意味/sします。
コンラッドボロウスキ

4

アトミックグループと所有量指定子を使用する

私は、原子団(い(?>...))と所有数量詞(?+*+++{m,n}+)ゴルフのために、時には非常に便利に。文字列と一致し、後でバックトラックを禁止します。そのため、正規表現エンジンによって検出された最初の一致可能な文字列にのみ一致します。

たとえばa、先頭に奇数の'があり、その後にa' が続かない文字列と一致させるには、次を使用できます。

^(aa)*+a
^(?>(aa)*)a

これにより.*、自由に使用することができ、明らかな一致がある場合、パターンを壊す可能性のある文字が多すぎたり少なすぎたりする可能性はもうありません。

.NET正規表現(所有量限定子を持たない)では、これを使用してグループ1を3の最大倍数(最大30回)でポップできます(あまりよくゴルフされません):

(?>((?<-1>){3}|){10})


4

部分式(PCRE)の後にキャプチャされたグループを忘れる

この正規表現の場合:

^((a)(?=\2))(?!\2)

グループ1の後の\ 2をクリアする場合は、再帰を使用できます。

^((a)(?=\2)){0}(?1)(?!\2)

aa前のものは一致しませんが、一致します。時には、??またはの?代わりに使用することもできます{0}

これは、再帰を頻繁に使用し、後方参照または条件付きグループの一部が正規表現のさまざまな場所にある場合に便利です。

また、PCREの再帰ではアトミックグループが想定されることに注意してください。したがって、これは単一の文字とは一致しませんa

^(a?){0}(?1)a

私はまだ他の味でそれを試しませんでした。

先読みの場合、この目的で二重ネガを使用することもできます。

^(?!(?!(a)(?=\1))).(?!\1)

4

オプションの式

覚えておくと便利な場合があります

(abc)?

、ほとんど同じ

(abc|)

ただし、小さな違いがあります。最初のケースでは、グループがキャプチャするabcか、まったくキャプチャしません。後者の場合、後方参照は無条件に失敗します。2番目の式では、グループはキャプチャするabcか、空の文字列を取得します。後者の場合、後方参照は無条件に一致します。後者の動作をエミュレートするには、?2バイトかかる別のグループのすべてを囲む必要があります。

((abc)?)

使用して|いるバージョンは、とにかく他の形式のグループで式をラップし、キャプチャを気にしない場合にも役立ちます。

(?=(abc)?)
(?=abc|)

(?>(abc)?)
(?>abc|)

最後に、このトリックは?、生の形式でもバイトを保存する貪欲な人にも適用できます(結果として、他の形式のグループと組み合わせると3バイトになります)。

(abc)??
(|abc)

1

常に一致する複数の先読み(.NET)

(部分式をキャプチャするために)常に一致する先読み構造が3つ以上ある場合、または先読みに数量詞があり、その後に何か他のものが続く場合、それらは必ずしもキャプチャされないグループにある必要があります。

(?=a)(?=b)(?=c)
((?=a)b){...}

これらは短いです:

(?(?(?(a)b)c))
(?(a)b){...}

where aは、キャプチャされたグループの名前であってはなりません。あなたは使用することはできません|で通常のものを意味するbc括弧の別のペアを追加することなく。

残念ながら、条件でグループのバランスをとるのはバグが多いように見え、多くの場合役に立たなくなりました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.