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]」を使うと移植可能です。