次: , 前: Regular Expressions, 上: Regular Expressions


33.2.1 正規表現の構文

正規表現では、数個の文字が特別な構成であり、残りは普通です。 普通の文字は、その文字だけに一致する単純な正規表現です。 特別な文字は、`.'、`*'、`+'、 `?'、`['、`]'、`^'、`$'、`\'であり、 将来新たな文字が定義されることはありません。 正規表現に現れるこれら以外の文字は、 まえに`\'がない限り普通の文字です。

たとえば、`f'は特別な文字ではないので普通の文字です。 ですから、`f'は文字列`f'だけに一致する正規表現です。 (これは文字列`ff'には一致しない。) 同様に、`o'は`o'だけに一致する正規表現です。

任意の2つの正規表現abを連結できます。 その結果は、aが文字列の始めの部分に一致し、かつ、 bがその文字列の残りに一致するときにその文字列に一致する 正規表現になります。

簡単な例として、正規表現 `f'と`o'を連結して 正規表現`fo'を得られます。 これは文字列`fo'だけに一致します。 これは明らかですね。 より強力なことをするには、特別な文字の1つを使う必要があります。 それらの一覧を以下に示します。

`.' (ピリオド)
特別な文字であり、改行以外の任意の1文字に一致する。 連結を使って`a.b'のような正規表現を作れる。 これは、`a'で始まり`b'で終る任意の3文字の文字列に一致する。
`*'
単独では構成要素ではない。 直前の正規表現を可能な限り反復することを意味する後置演算子である。 すなわち、`o*'は(`o'が存在しない場合も含めて) 任意個の`o'に一致する。

`*'はつねに先行する最小の正規表現に適用される。 したがって、`fo*'は`fo'を繰り返すのではなく、 `o'を繰り返す。 この正規表現は`f'、`fo'、`foo'などに一致する。

`*'を用いた構成の一致を処理するときには、 ただちに得られる限りの反復回数に展開される。 そうしてから、残りのパターンを処理する。 一致に失敗するとバックトラック(後戻り)が発生して、 `*'を用いた構成の反復回数を減らして パターンの残りの部分が一致できるようにする。 たとえば、文字列`caaar'に対して `ca*ar'を一致させることを考えてみる。 始めに、`a*'を3つの`a'すべてに一致させようとする。 しかし、残りのパターンが`ar'なのに`r'しか残っていないため、 この試みは失敗する。 そこで、つぎは`a*'を`a'2つだけに一致させる。 こうすると、残りの正規表現も正しく一致する。

入れ子にした反復演算子がバックトラックのループを指定する場合、 それはとても遅くなる。 たとえば、正規表現`\(x+y*\)*a'を `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz'の列に一致させると 最終的に失敗するまで何時間も費してしまう。 遅さの原因は、Emacsは35個の`x'をグループに分ける各方法を すべて試してからでないとそれらが一致しないことを結論できないからである。 読者の正規表現が素早く動作することを保証するために、 入れ子になった繰り返しを注意深く調べること。

`+'
`*'に似た後置演算子だが、 直前の正規表現に1回以上一致する必要がある。 たとえば、`ca+r'は、文字列`car'や`caaaar'には一致するが、 文字列`cr'には一致ない。 一方、`ca*r'の場合は、上記の3つすべてに一致する。
`?'
`*'に似た後置演算子だが、 直前の正規表現に1回だけ一致するか、あるいは、1回も一致しない。 たとえば、`ca?r'は、`car'や`cr'に一致するが、 他のものには一致しない。
`[ ... ]'
`['で始まり`]'で終る文字選択を表す。 もっとも単純な場合は、 この2つの中括弧のあいだにある文字の1つ1つがこの文字選択に一致する。

したがって、`[ad]'は、`a'1文字か`d'1文字のどちらにも一致する。 `[ad]*'は、`a'と`d'だけから成る (空の文字列を含む)任意の文字列に一致する。 このことから、`c[ad]*r'は、 `cr'、`car'、`cdr'、`caddaar'などに一致することがわかる。

文字選択には、文字範囲の指定を含めることもでき、 始めの文字と終りの文字のあいだに`-'を書く。 つまり、`[a-z]'はすべてのASCII小英文字に一致する。 範囲指定と個々の文字を自由に織り混ぜてよく、 `[a-z$%.]'のように書ける。 これは、任意のASCII小英文字、`$'、`%'、ピリオドに一致する。

正規表現`[\200-\377]'で すべての非ASCII文字につねに一致するとは限らない。 ユニバイト(see Text Representations)のバッファや文字列を 探索するときにはうまく働くが、マルチバイトのバッファや文字列では 多くの非ASCII文字のコードは8進数0377より大きいために働かない。 しかし、正規表現`[^\000-\177]'は、 ASCII文字のみを除外しているため、 マルチバイト表現でもユニバイト表現でもすべての非ASCII文字に一致する。

範囲指定の始めと終りは同じ文字集合(see Character Sets)に 属している必要がある。 したがって、`[a-\x8e0]'は正しくない。 `a'はASCII文字集合に属し、 文字0x8e0(グレーブアクセント付き`a')は EmacsのLatin-1の文字集合に属しているからである。

正規表現の普通の特別な文字は、文字選択の内側では特別ではないことに注意。 文字選択の内側では、まったく別の文字の集まり、 `]'、`-'、`^'が特別である。

文字選択に`]'を含めるには、 `]'を最初の文字として指定する必要がある。 たとえば、`[]a]'は、`]'や`a'に一致する。 `-'を含めるには、`-'を文字選択の最初の文字か 最後の文字として書くか、範囲指定のあとに置く。 したがって、`[]-]'は、`]'と`-'の両方に一致する。

文字選択に`^'を含めるには、`^'を文字選択の2番目以降に置く。

`[^ ... ]'
`[^'は文字選択の補集合の始まりを意味し、 指定した文字を除く任意の文字に一致する。 すなわち、`[^a-z0-9A-Z]'は、 英文字と数字文字を除くすべての文字に一致する。

`^'は文字選択の先頭になければ文字選択では特別な意味を持たない。 `^'に続く文字は先頭にあるものとして扱われる (いいかえれば、ここでは`-'や`]'は特別な意味を持たない)。

文字選択の補集合は、一致しない文字として改行を指定しない限り、 改行にも一致する。 この点は、grepのようなプログラムでの正規表現の扱い方と対照的である。

`^'
空の文字列に一致する特別な文字であり、 一致を取る対象のテキストの行頭のみに一致する。 それ以外では、一致に失敗する。 したがって、`^foo'は、行頭にある`foo'に一致する。

バッファのかわりに文字列と一致を取るときには、 `^'は文字列の先頭や改行文字`\n'のうしろに一致する。

`$'
`^'と同様だが行末のみに一致する。 したがって、`x+$'は、 行末にある1文字以上の`x'から成る文字列に一致する。

バッファのかわりに文字列と一致を取るときには、 `$'は文字列の末尾や改行文字`\n'のまえに一致する。

`\'
2つの機能がある。 (`\'を含む)特別な文字をクォートする(意味を抑える)ことと、 特別な構成を導入することである。

`\'は特別な文字をクォートするので、 `\$'は文字`$'だけに一致する正規表現、 `\['は文字`['だけに一致する正規表現、 といった具合になる。

`\'にはLisp文字列の入力構文(see String Type)でも 特別な意味があり、`\'でクォートする必要があることに注意してほしい。 たとえば、文字`\'に一致する正規表現は`\\'である。 文字群`\\'を含むLisp文字列を書くには、各`\'をクォートするために `\'が必要である。 したがって、`\'に一致する正規表現の入力構文は"\\\\"である。

注意: 従来との互換性のために、 特別な文字がそれらの特別な意味をなしえない文脈で使われた場合には、 普通の文字として扱われる。 たとえば、`*foo'では、`*'の対象となる正規表現が直前にないため、 `*'は普通の文字として扱われる。 このようなふるまいに依存することはよいことではない。 特別な文字は書く位置に関係なくクォートするべきである。

多くの場合、任意の文字を伴う`\'はその文字だけに一致します。 しかし、いくつか例外があって、 `\'で始まる2文字列が特別な意味を持つ場合があります。 (2文字目にくる文字は、 単独で使った場合にはつねに普通の文字として扱われる。) 以下に`\'の構成を示します。

`\|'
選択肢を指定する。 `\|'をあいだに伴った2つの正規表現abは、 abのいずれかに一致する文字列に一致する正規表現となる。

したがって、`foo\|bar'は、`foo'や`bar'に一致するが、 それ以外の文字列には一致しない。

`\|'は、周囲にある適用しうる正規表現の中でも最大のものに適用される。 `\|'によるグループ化を制限するのは、 これを囲む`\( ... \)'によるグループ化だけである。

何度`\|'を使っても処理できるだけの十分なバックトラック能力がある。

`\( ... \)'
以下の3つの目的を果たすグループ化のための構成。
  1. 他の操作に使うために一連の選択肢`\|'を括る。 したがって、`\(foo\|bar\)x'は、 `foox'か`barx'のいずれかに一致する。
  2. 後置演算子、`*'、`+'、`?'を適用できるように、 複雑な正規表現を括る。 したがって、`ba\(na\)*'は、 `bananana'のように、(0個以上の)任意個の 文字列`na'に一致する。
  3. あとで参照できるように、一致した部分文字列を記録する。

最後の使い方は、括弧によるグループ化という考え方から 派生したものではない。 同一の`\( ... \)'構成に与えた2つめの別の機能である。 実用上、これら2つの意味が混同されることはないからである。 この機能をつぎに説明する。

`\digit'
d番目に現れた`\( ... \)'に一致したテキストと 同じテキストに一致する。

いいかえれば、一致を処理するときには、 `\( ... \)'構成の末尾に達すると、 この構成に一致したテキストの始めと終りを記録する。 そして、正規表現のそれよりうしろでは、 『d番目に現れた`\( ... \)'に一致したテキスト』という意味で それがなんであろうと`\'に続けて数字dを使える。

1つの正規表現内に現れる最初の9個の`\( ... \)'に一致する文字列には、 正規表現中で開き括弧が現れた順に、1から9までの番号を割り振る。 そのため、`\1'から`\9'で、 対応する`\( ... \)'に一致したテキストを参照できる。

たとえば、`\(.*\)\1'は、改行を含まない文字列で、かつ、 前半と後半が同一である文字列に一致する。 `\(.*\)'は前半部分に一致し、それはどのようなものでもかまわない。 一方、それに続く`\1'は、 前半部分とまったく同じテキストに一致しなければならない。

`\w'
任意の単語構成文字に一致する。 エディタの構文テーブルによってこの文字が決まる。 see Syntax Tables
`\W'
単語構成文字以外の文字に一致する。
`\scode'
構文コードがcodeである文字だけに一致する。 ここで、codeは構文コードを表す文字である。 つまり、`w'は単語構成要素を、 `-'は白文字を、`('は開き括弧を表すといった具合である。 白文字の構文を表すには、`-'か空白のいずれかを使う。 構文コードとそれらを表す文字の一覧については、 see Syntax Class Table
`\Scode'
構文がcodeでない任意の文字に一致する。

つぎの正規表現は空の文字列に一致します。 つまりこれらは文字を使用しませんが、 これらが一致するかどうか文脈に依存します。

`\`'
空の文字列に一致するが、 一致対象であるバッファや文字列の先頭に限る。
`\''
空の文字列に一致するが、 一致対象であるバッファや文字列の末尾に限る。
`\='
空の文字列に一致するが、ポイント位置に限る。 (文字列に対する一致ではこの構文は定義されない。)
`\b'
空の文字列に一致するが、単語の先頭や末尾に限る。 したがって、`\bfoo\b'は、単語として独立して現れる`foo'に一致する。 `\bballs?\b'は、単語として独立して現れる `ball'や`balls'に一致する。

`\b'は、 バッファの先頭や末尾にあるテキストとは無関係に、 バッファの先頭や末尾にも一致する。

`\B'
空の文字列に一致するが、単語の先頭や末尾以外に限る。
`\<'
空の文字列に一致するが、単語の先頭に限る。 `\<'はバッファの先頭にも一致するが、単語構成文字が続く場合に限る。
`\>'
空の文字列に一致するが、単語の末尾に限る。 `\>'はバッファの末尾にも一致するが、 単語構成文字で終了している場合に限る。

任意の文字列が正しい正規表現ではありません。 たとえば、(`[]]'のような少数の例外を除けば) 角括弧が対応していない文字列は正しくありませんし、 1つの`\'で終る文字列も正しくありません。 不正な正規表現を探索関数に渡すと、 エラーinvalid-regexpが通知されます。

— 機能: regexp-quote string

この関数は、stringだけに正確に一致する正規表現の文字列を返す。 これにより、正規表現を必要とする関数を呼び出すときに この文字列だけに正確に一致できる。

          (regexp-quote "^The cat$")
               => "\\^The cat\\$"
     

regexp-quoteの用途の1つは、 正規表現で記述された文脈に正確に一致する文字列を組み合わせることである。 たとえば、つぎは、白文字で囲まれたstringの値で表される文字列を探索する。

          (re-search-forward
           (concat "\\s-" (regexp-quote string) "\\s-"))
     
— 機能: regexp-opt strings &optional paren

この関数は、文字列stringsのいずれかに一致する 効率よい正規表現を返す。 これは、たとえばフォントロック(font-lock)モードなどで、 可能な限り高速な一致や探索を行う必要がある場合に有用である。

省略可能な引数parennil以外であると、 返される正規表現はつねに少なくとも1つの括弧によるグループ構文で囲まれる。

つぎのregexp-optの簡略版定義は、 実際の値に等価な(ただしそれほど効率よくない)正規表現を生成する。

          (defun regexp-opt (strings paren)
            (let ((open-paren (if paren "\\(" ""))
                  (close-paren (if paren "\\)" "")))
              (concat open-paren
                      (mapconcat 'regexp-quote strings "\\|")
                      close-paren)))
     
— 機能: regexp-opt-depth regexp

この関数は、regexp内のグループ化構文(括弧で括った式)の 総個数を返す。