web-dev-qa-db-ja.com

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

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

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

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

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

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

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

基本的な正規表現 (BRE)

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

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

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

  • \{m,n\}は、mからn回の間の直前の文字または部分式に一致します。 nまたはmは省略でき、\{m\}は正確にmを意味します。
  • 括弧内では 文字クラス を使用できます。たとえば、[[:alpha:]]は任意の文字に一致します。 ブラケット式 )の最新の実装には、[.ll.]のような collat​​ing elements[=a=]のような等価クラスも含まれます。

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

  • 代替の\|foo\|barfooまたはbarに一致します。
  • \?\{0,1\}の省略形)および\+\{1,\}の省略形)は、直前の文字または部分式とそれぞれ最大で1回、または少なくとも1回一致します。
  • \nは改行に一致し、\tはタブに一致します。
  • \wは、任意のWord構成要素([_[:alnum:]]の省略形ですが、ローカリゼーションに関してはバリエーションがあります)に一致し、\Wは、Word構成要素ではない任意の文字に一致します。
  • \<および\>は、それぞれWordの先頭または末尾でのみ空の文字列に一致します。 \bはどちらかに一致し、\B\bが一致しない場所に一致します。

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

拡張正規表現 (ERE)

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

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

PCRE(Perl互換の正規表現)

PCREはEREの拡張機能で、元々 Perl で導入され、GNU grep -Pおよび多くの最新のツールとプログラミング言語]で採用されています、通常 [〜#〜] pcre [〜#〜] ライブラリを介します。例付きの素敵なフォーマットについては Perlのドキュメント を参照してください。最新バージョンのすべての機能とは限りませんPCREはPerlの一部をサポートしています(Perlコードの実行はPerlでのみサポートされています)。サポートされている機能の概要については PCREマニュアル を参照してください。

  • (?:…)は、キャプチャしないグループです。(…)と同様ですが、後方参照は考慮されません。
  • (?=FOO)BAR(先読み)はBARに一致しますが、同じ位置から始まるFOOにも一致する場合のみです。これは、一致に次のテキストを含めずに一致をアンカーする場合に最も役立ちます:foo(?=bar)fooに一致しますが、その後にbarが続く場合のみ。
  • (?!FOO)BAR(負の先読み)はBARに一致しますが、同じ位置にあるFOOにも一致しません。たとえば、(?!foo)[a-z]+は、fooで始まらないすべての小文字のWordに一致します。 [a-z]+(?![0-9)は、数字が後に続かない小文字のWordと一致します(したがって、foo123では、foと一致しますが、fooとは一致しません)。
  • (?<=FOO)BAR(lookbehind)はBARに一致しますが、その直前にFOOが一致する場合のみです。 FOOの長さは既知である必要があります(*などの繰り返し演算子は使用できません)。これは、前のテキストを一致に含めずに一致をアンカーする場合に最も便利です。(?<=^| )foofooに一致しますが、その前にスペースまたは文字列の先頭がある場合のみです。
  • (?<!FOO)BAR(負の後読み)はBARに一致しますが、直前にFOOが一致しない場合のみです。 FOOの長さは既知である必要があります(*などの繰り返し演算子は使用できません)。これは、前のテキストを一致に含めずに一致をアンカーする場合に最も役立ちます。(?<![a-z])foofooに一致しますが、前に小文字がない場合のみです。

Emacs

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

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

シェル globs

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

  • ?は、任意の1文字と一致します。
  • […]は、一般的な正規表現構文と同様の文字セットです。一部のシェルは文字クラスをサポートしていません。一部のシェルでは、セットを無効にするために!ではなく^が必要です。
  • *は、任意の文字シーケンスに一致します(ファイルパスの一致時に/を除くことがよくあります。/*から除外されている場合、**には/が含まれることがありますが、ツールのドキュメントを確認してください)。
  • バックスラッシュは次の文字を引用します。

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