正規表現がXでは機能するがYでは機能しないのはなぜですか?


77

特定のプログラム(grep、sed、awk、perl、python、ruby、ksh、bash、zsh、find、emacs、vi、vim、geditなど)でうまく機能する正規表現を作成しました。しかし、別のプログラム(または別のUNIXバリアント)で使用すると、マッチングが停止します。どうして?

回答:


103

残念ながら、歴史的な理由により、ツールごとに正規表現の構文がわずかに異なります。また、一部の実装には、他のツールではサポートされない拡張機能がある場合があります。共通の根拠がありますが、すべてのツール作成者がいくつかの異なる選択をしたようです。

その結果、あるツールで機能する正規表現がある場合、別のツールで機能するように変更する必要がある場合があります。一般的なツールの主な違いは次のとおりです。

  • 演算子に+?|(){}バックスラッシュが必要かどうか。
  • 基本.[]*^$を超えてサポートされる拡張機能と通常は+?|()

この回答では、主な標準をリストしています。詳細については、使用しているツールのドキュメントを確認してください。

ウィキペディアの正規表現エンジン比較には、一般的な実装でサポートされている機能をリストした表があります。

基本的な正規表現(BRE)

基本的な正規表現は、POSIX標準によって体系化されていますgrepsedおよびで使用される構文viです。この構文は次の機能を提供します。

  • ^そして$、行の最初と最後でのみ一致します。
  • . 任意の文字(または改行を除く任意の文字)に一致します。
  • […]括弧内にリストされた任意の1文字(文字セット)に一致します。左大括弧の後の最初の文字がaの^場合、リストされていない文字が代わりに一致します。を含めるには]、開始の直後[(または[^負のセットの場合は後)に置きます。-が2文字の間にある場合、範囲を示します。リテラルを含めるには、-範囲として解析できない場所に置きます。
  • ^$.*\[次の文字を引用符で囲む前にバックスラッシュを付けます。
  • * 先行する文字または部分式に0回、1回以上一致します。
  • \(…\)*演算子または後方参照と\DIGIT置換で使用するための構文グループです。
  • 後方参照は\1\2、...、対応するグループにマッチした正確なテキストと一致する例えば\(fo*\)\(ba*\)\1マッチfoobaafooではなくfoobaafo。10番目以降のグループを参照する標準的な方法はありません(の標準的な意味\10は、最初のグループの後にが続き0ます)。

次の機能も標準ですが、一部の制限された実装にはありません。

  • \{m,n\}間の直前の文字または部分式と一致Mのn倍; nまたはmは省略でき、正確にmを意味します。\{m\}
  • 角かっこ内では、文字クラスを使用できます[[:alpha:]]。たとえば、任意の文字に一致します。ブラケット式の近代的な実装)のような照合要素とのような[.ll.]同等クラスも含む[=a=]

以下は一般的な拡張(特にGNUツール)ですが、すべての実装で見られるわけではありません。使用しているツールのマニュアルを確認してください。

  • \|代替の場合:foo\|bar一致fooまたはbar
  • \?(の略\{0,1\})および\+(の略\{1,\})は、それぞれ最大で1回、または少なくとも1回、先行する文字または部分式に一致します。
  • \n改行、\tタブなどに一致します。
  • \w単語の構成要素([_[:alnum:]]ローカライズに関しては短縮形ですが)に\W一致し、単語の構成要素ではない文字に一致します。
  • \<また\>、単語の先頭または末尾でのみ空の文字列に一致します。\bいずれかに\B一致\bし、一致しない場所に一致します。

\|演算子のないツールは、正規表現のすべての力を備えていないことに注意してください。後方参照を使用すると、数学的な意味で正規表現では実行できないいくつかの余分なことが可能になります。

拡張正規表現(ERE)

拡張正規表現は、POSIX標準によって体系化されています。BREに対する主な利点は規則性です。すべての標準演算子は裸の句読点文字であり、句読点文字の前のバックスラッシュは常に引用符です。それはで使用される構文であるawkgrep -Eまたはegrep、GNU sed -r、およびbashのの=~オペレーター。この構文は次の機能を提供します。

  • ^そして$、行の最初と最後でのみ一致します。
  • . 任意の文字(または改行を除く任意の文字)に一致します。
  • […]括弧内にリストされた任意の1文字(文字セット)に一致します。初期値^と範囲の補完は、BREのように機能します(上記を参照)。文字クラスを使用できますが、いくつかの実装にはありません。最新の実装では、等価クラスと照合要素もサポートしています。大括弧内のバックスラッシュは、すべてではありませんがいくつかの実装で次の文字を引用します。\\移植性のためのバックスラッシュを意味するために使用します。
  • (…)は、置換*または\DIGIT置換用の構文グループです。
  • |代替の場合:foo|bar一致fooまたはbar
  • *+および?前の文字または部分式に何度も一致します:0以上の場合*、1以上の場合+、0または1の場合?
  • バックスラッシュは、英数字でない場合、次の文字を引用します。
  • {m,n}間の直前の文字または部分式と一致し、MN倍(一部の実装から欠落します)。nまたはmは省略でき、正確にmを意味します。{m}
  • BREのようないくつかの一般的な拡張機能:後方参照(特に使用できるbusybox実装を除いてawkにはありません); 特殊文字、など。単語境界and 、単語構成要素and 、…\DIGIT$0 ~ "(...)\\1"\n\t\b\B\b\B

PCRE(Perl互換の正規表現)

PCREはEREの拡張であり、もともとPerlによって導入され、GNU grep -Pおよび多くの最新のツールとプログラミング言語で採用され、通常はPCREライブラリを介して行われます。例付きの素晴らしいフォーマットについては、Perlのドキュメントを参照してください。PCREでは、Perlの最新バージョンのすべての機能がサポートされているわけではありません(たとえば、Perlコードの実行はPerlでのみサポートされています)。サポートされている機能の概要については、PCREのマニュアルを参照してください。EREへの主な追加は次のとおりです。

  • (?:…)は非キャプチャグループです:など(…)ですが、後方参照にはカウントされません。
  • (?=FOO)BAR(lookahead)は一致BARしますがFOO、同じ位置から開始するための一致もある場合のみです。これは、試合中に次のテキストを含めずに試合を固定するために最も有用である:foo(?=bar)マッチfooそれは続いていますが、場合にのみbar
  • (?!FOO)BAR(負の先読み)は一致BARしますがFOO、同じ位置に一致するものはありません。たとえば(?!foo)[a-z]+foo; で始まらない小文字の単語に一致します。[a-z]+(?![0-9)数字が後に続かない小文字の単語に一致します(つまりfoo123、一致しますfoが一致しませんfoo)。
  • (?<=FOO)BAR(後読み)は一致しますがBAR、直前にが一致する場合のみですFOOFOO長さがわかっている必要があります(などの繰り返し演算子は使用できません*)。これは、マッチにマッチする前のテキストを含めずにマッチをアンカーするために最も便利です:(?<=^| )fooマッチfooがスペースまたは文字列の先頭によって先行される場合のみ。
  • (?<!FOO)BAR(負の後読み)は一致しますがBAR、の一致が直前にない場合のみですFOOFOO長さがわかっている必要があります(などの繰り返し演算子は使用できません*)。これは、マッチにマッチする前のテキストを含めずにマッチを固定するのに最も便利です:(?<![a-z])fooマッチfooするのは小文字が前にない場合のみです。

Emacs

Emacsの構文は、BREとEREの中間です。Emacsに加えて、これは-regexGNU findのデフォルトの構文です。Emacsは次の演算子を提供します:

  • ^$.[…]*+?EREのように
  • \(…\)\|\{…\}、BREのように\DIGIT
  • より多くのバックスラッシュ文字シーケンス\<そして、\>単語の境界について、Emacsの最近のバージョンでは、Emacsに似た構文を持つ他のエンジンではサポートされないことがよくあります。

シェルグロブ

シェルグロブ(ワイルドカード)は、正規表現とはまったく異なり、強力ではない構文でパターンマッチングを実行します。シェルに加えて、これらのワイルドカードはfind -name、rsyncフィルターなどの他のツールで使用できます。POSIXパターンには次の機能が含まれます。

  • ? 任意の1文字に一致します。
  • […]一般的な正規表現の構文のような文字セットです。一部のシェルは、文字クラスをサポートしていません。一部のシェルでは、セットを無効にする!代わりに必要です^
  • *(多くの場合を除き、任意の文字列に一致する/ファイルパスを一致させる際、場合/から除外され*、そして**時には含まれ/ますが、ツールのマニュアルを参照してください)。
  • バックスラッシュは次の文字を引用します。

Kshは、正規表現の全機能にパターンマッチングを提供する追加機能を提供します。これらの機能は、実行後にbashでも使用できますshopt -s extglob。Zshの構文異なりますが、の後のkshの構文もサポートできますsetopt ksh_glob


あなたが言及したいと思うかもしれない他の豊富な REは、のようなものvimとAT&T libast(のようにksh93)のものです。
ステファンシャゼル

@StéphaneChazelasvimとは別に、vim正規表現を使用するプログラムは何ですか?ksh以外に、どのプログラムがlibastを使用していますか?
ジル14

AT&Tツールセットのすべては、AT&TのRE(使用していますgreptwexpr...)を。ただしksh、そのツールセットはAT&T以外ではめったに見つかりません。
ステファンシャゼル

私の理解(およびウィキペディアの)によれば、あなたの用語「文字クラス」は実際には「POSIX文字クラス」を指します...しかし、regex(7)あなたに同意し、[these]「括弧表現」および(「括弧表現」内で)[:these:]「文字クラス」と呼びます。どのように対処するのが最適かわかりません。
アダム・カッツ

あなたがそれらを呼ぶものは何でも、彼らは範囲をサポートします。-範囲を指定し、最初に(オプションの^)後にエスケープするか、文字どおりに使用する場合は最後にエスケープする必要があることに注意してください。(たとえば[A-z]、大文字と小文字の変更に注意してください。コード65〜122の文字に一致し、誤って次の各文字を含むバグがたくさんあります[\]^_`。また[!-~]、ANSIのすべての印刷可能文字に一致する有効かつわかりにくい文字もあります。、これは私のように見ることを好む[\x21-\x7e]異なる次元の混乱しかしその作用に少なくとも簡単ですこれは、)。
アダム・カッツ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.