このページの内容

3.7 問題のある正規表現

一部の文字列は無効な正規表現であり、grepは診断メッセージを表示して失敗します。たとえば、「xy\1」は、後方参照「\1」の参照先となる括弧内の部分式がないため無効です。

また、一部の正規表現の動作は未規定で、現在grepが診断しなくても使うべきではありません。たとえば、「xy\0」は、「0」が特殊文字ではなく、「\0」も特殊なバックスラッシュ表現ではないため、動作が未規定です(「特殊なバックスラッシュ表現」を参照)。未規定の動作は、一致する文字列の集合が一部しか定まっていない場合、まったく定まっていない場合、さらには式自体が無効な場合もあり、特に問題となります。

次の正規表現構成は、POSIXに準拠するすべてのプラットフォームで無効です。そのため、移植可能なスクリプトでは、grepがこれらの構成を拒否すると想定できます。

  • 後方参照「\n」より前にある閉じ括弧の数がn個未満の基本正規表現です。たとえば、「\(a\)\2」は無効です。
  • 文字クラスを開始しない「[:」を含む角括弧式です。「[=」と「[.」についても同様です。たとえば、「[a[:b]」と「[a[:ouch:]b]」は無効です。

GNU grepは、次の構成を無効として扱います。ただし、ほかのgrep実装では許す場合があるため、移植可能なスクリプトは、これらが無効であることに依存すべきではありません。

  • 正規表現の末尾にある、エスケープされていない「\」です。
  • 角括弧式を開始しない、エスケープされていない「[」です。
  • 区間式を開始しない、基本正規表現内の「\{」です。
  • 「\(」と「\)」が釣り合わない基本正規表現、または対応する閉じ括弧がない「(」を含む拡張正規表現です。
  • POSIXロケールで、要素が0個になる「z-a」のような範囲式です。GNU以外のgrepは、何にも一致しない有効な範囲として扱う場合があります。
  • 繰り返し回数が32767を超える区間式です。(移植可能なPOSIXの上限は255です。また、回数がより少ない区間式でも、既知のどの実装でも、実用にならないほど遅い場合があります。)
  • 3つ以上の要素を含み、最初と最後がどちらも「:」、どちらも「.」、またはどちらも「=」である角括弧式です。たとえば、GNU以外のgrepは「[:alpha:]」を「[[:alpha:]]」や「[:ahlp]」と同じように扱う場合があります。

次の構成は、GNU grepでは動作が明確に定義されています。ただし、ほかでは動作が未規定のため、移植可能なスクリプトでは避けるべきです。

  • 「\b」、「\<」、「\]」のような特殊なバックスラッシュ表現です。「特殊なバックスラッシュ表現」を参照してください。
  • 「\?」、「\+」、「\|」を使う基本正規表現です。
  • 後方参照を使う拡張正規表現です。
  • 空の正規表現、部分式、選択肢です。たとえば、「(a|bc|)」は移植可能ではありません。同等の移植可能な式は「(a|bc)?」です。
  • 基本正規表現内で、「\(」の直後にあるアンカー「^」、または「\)」の直前にあるアンカー「$」です。
  • 基本正規表現内で、別の繰り返し演算子の直後にある繰り返し演算子です。
  • 拡張正規表現内で、有効な区間式を開始しない、エスケープされていない「{」です。GNU grepは、その「{」を通常の文字として扱います。
  • パターンまたは入力データにあるNUL文字や符号化エラーです。「文字符号化」を参照してください。
  • 改行以外の文字で終わる入力ファイルです。GNU grepは、黙って改行を補います。

次の構成は、GNUとほかのgrep実装の両方で動作が未規定です。スクリプトでは、可能な限り避けるべきです。

  • 通常の文字をエスケープするバックスラッシュです。ただし、「\1」のような後方参照や、「\<」、「\b」のような特殊なバックスラッシュ表現は除きます。「特殊なバックスラッシュ表現」を参照してください。たとえば、「\x」は現在動作が未規定ですが、将来のgrepでは「\x」に新しい動作を定義する場合があります。
  • アンカーの直後、または正規表現全体、括弧で囲まれた部分式、選択肢の先頭にある繰り返し演算子です。たとえば、「+|^*(+a|?-b)」は動作が未規定ですが、「\+|^\*(\+a|\?-b)」は移植可能です。
  • POSIX以外のロケールでの範囲式です。たとえば、一部のロケールでは「[a-z]」が小文字の字母以外の文字に一致したり、一部の小文字の字母に一致しなかったり、無効だったりする場合があります。GNU grepでは、こうした範囲式に元のコードポイントを使うのか、LC_COLLATEカテゴリーが指定する照合順序を使うのか、sortやstrcollが使う照合順序を使うのか、ほかの解釈をするのかは文書化されていません。POSIX以外のロケールで小文字の字母に一致させるには「[[:lower:]]」、ASCIIの小文字に一致させるには「[abcdefghijklmnopqrstuvwxyz]」を使うと移植可能です。