GNU/Linux >> Linux の 問題 >  >> Linux

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

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

承認された回答:

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

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

  • 演算子が+?|(){}かどうか バックスラッシュが必要です;
  • 基本的な。[]*^ $以外でサポートされている拡張機能 通常は+?|()

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

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

基本的な正規表現(BRE)

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

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

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

  • { 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に対する主な利点は規則性です。すべての標準演算子は裸の句読文字であり、句読文字の前にバックスラッシュが常に引用されます。これは、 awkで使用される構文です。 grep -E またはegrep 、GNU sed -r 、およびbashの=〜 オペレーター。この構文は、次の機能を提供します。

  • ^ および$ 行の最初と最後でのみ一致します。
  • 任意の文字(または改行以外の任意の文字)に一致します。
  • […] 角かっこ(文字セット)内にリストされている任意の1文字に一致します。最初の^による補完 範囲はBREのように機能します(上記を参照)。文字クラスを使用できますが、いくつかの実装にはありません。最新の実装は、等価クラスと照合要素もサポートしています。括弧内の円記号は、すべてではありませんが一部の実装では次の文字を引用します。 \を使用する 移植性のためのバックスラッシュを意味します。
  • (…) *で使用する構文グループです。 またはDIGIT 交換。
  • | 交互の場合: foo | bar fooに一致します またはbar
  • * + および 前の文字または部分式に何度も一致します: *の場合は0以上 、 +の場合は1つ以上 、の場合は0または1 。
  • 英数字でない場合、バックスラッシュは次の文字を引用します。
  • { m n } m間の前の文字または部分式に一致します およびn 時間(いくつかの実装から欠落); 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のドキュメントを参照してください。最新バージョンのPerlのすべての機能がPCREでサポートされているわけではありません(たとえば、Perlコードの実行はPerlでのみサポートされています)。サポートされている機能の概要については、PCREマニュアルを参照してください。 EREへの主な追加は次のとおりです。

  • (?:…) キャプチャしないグループです:(…)のように 、ただし、後方参照にはカウントされません。
  • (?=FOO)BAR (先読み)は BARと一致します 、ただし、 FOOにも一致する場合のみ 同じ位置から開始します。これは、一致に次のテキストを含めずに一致を固定するのに最も役立ちます: foo(?=bar) fooに一致します ただし、その後に barが続く場合に限ります 。
  • (?! FOO)BAR (負の先読み)は BARに一致します 、ただし、 FOOに一致するものもありません 同じ位置に。例:(?! foo)[a-z] + fooで始まらない小文字の単語に一致します; [a-z] +(?![0-9) 数字が続かない小文字の単語に一致します(したがって、 foo123 foと一致します ただし、 fooではありません 。
  • (?<=FOO)BAR (後ろ向き)は BARと一致します 、ただし、直前に FOOの一致がある場合のみ 。 FOO 既知の長さである必要があります( *などの繰り返し演算子は使用できません )。これは、前のテキストを一致に含めずに一致を固定するのに最も役立ちます:(?<=^ |)foo fooに一致します ただし、前にスペースまたは文字列の先頭が付いている場合に限ります。
  • (?<!FOO)BAR (ネガティブルックビハインド) BARに一致 、ただし、直前に FOOの一致がない場合のみ 。 FOO 既知の長さである必要があります( *などの繰り返し演算子は使用できません )。これは、前のテキストを一致に含めずに一致を固定するのに最も役立ちます:(?<![a-z])foo fooに一致します ただし、先頭に小文字が付いていない場合に限ります。

Emacs

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

  • ^ $ […] * + EREのように
  • (…) |{…} DIGIT BREのように
  • より多くのバックスラッシュ文字シーケンス。 < および> 単語の境界の場合。さらに最近のバージョンのEmacsでは、Emacsのような構文を持つ他のエンジンではサポートされていないことがよくあります。
関連:findを使用して特定のディレクトリを検索し、1つのディレクトリを除くその中のすべてのファイルを削除しますか?

シェルグロブ

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

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

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


Linux
  1. 一部のコマンドでBashプロセス置換が機能しないのはなぜですか?

  2. ファイルが存在する場合にforループの`zip`が機能するのに、存在しない場合は機能しないのはなぜですか?

  3. ヒアドキュメントの親シェルがダッシュのサブコマンドでは機能しないのに、Bashは機能するのはなぜですか?

  1. find -exec mv {} ./target/ + が機能しないのはなぜですか?

  2. sed の正規表現で `\d` が機能しないのはなぜですか?

  3. Chrome デベロッパー ツールで JavaScript を編集できないのはなぜですか?

  1. `md5sum`がインターネットと同じハッシュを与えないのはなぜですか?

  2. ブータブル USB の作成に 'dd' が機能しないのはなぜですか?

  3. この正規表現が Linux で機能しないのはなぜですか?