次: Regexp Example, 前: Regular Expressions, 上: Regular Expressions
正規表現では、数個の文字が特別な構成であり、残りは普通です。 普通の文字は、その文字だけに一致する単純な正規表現です。 特別な文字は、`.'、`*'、`+'、 `?'、`['、`]'、`^'、`$'、`\'であり、 将来新たな文字が定義されることはありません。 正規表現に現れるこれら以外の文字は、 まえに`\'がない限り普通の文字です。
たとえば、`f'は特別な文字ではないので普通の文字です。 ですから、`f'は文字列`f'だけに一致する正規表現です。 (これは文字列`ff'には一致しない。) 同様に、`o'は`o'だけに一致する正規表現です。
任意の2つの正規表現aとbを連結できます。 その結果は、aが文字列の始めの部分に一致し、かつ、 bがその文字列の残りに一致するときにその文字列に一致する 正規表現になります。
簡単な例として、正規表現 `f'と`o'を連結して 正規表現`fo'を得られます。 これは文字列`fo'だけに一致します。 これは明らかですね。 より強力なことをするには、特別な文字の1つを使う必要があります。 それらの一覧を以下に示します。
`*'はつねに先行する最小の正規表現に適用される。 したがって、`fo*'は`fo'を繰り返すのではなく、 `o'を繰り返す。 この正規表現は`f'、`fo'、`foo'などに一致する。
`*'を用いた構成の一致を処理するときには、 ただちに得られる限りの反復回数に展開される。 そうしてから、残りのパターンを処理する。 一致に失敗するとバックトラック(後戻り)が発生して、 `*'を用いた構成の反復回数を減らして パターンの残りの部分が一致できるようにする。 たとえば、文字列`caaar'に対して `ca*ar'を一致させることを考えてみる。 始めに、`a*'を3つの`a'すべてに一致させようとする。 しかし、残りのパターンが`ar'なのに`r'しか残っていないため、 この試みは失敗する。 そこで、つぎは`a*'を`a'2つだけに一致させる。 こうすると、残りの正規表現も正しく一致する。
入れ子にした反復演算子がバックトラックのループを指定する場合、
それはとても遅くなる。
たとえば、正規表現`\(x+y*\)*a'を
`xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz'の列に一致させると
最終的に失敗するまで何時間も費してしまう。
遅さの原因は、Emacsは35個の`x'をグループに分ける各方法を
すべて試してからでないとそれらが一致しないことを結論できないからである。
読者の正規表現が素早く動作することを保証するために、
入れ子になった繰り返しを注意深く調べること。
したがって、`[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番目以降に置く。
`^'は文字選択の先頭になければ文字選択では特別な意味を持たない。 `^'に続く文字は先頭にあるものとして扱われる (いいかえれば、ここでは`-'や`]'は特別な意味を持たない)。
文字選択の補集合は、一致しない文字として改行を指定しない限り、
改行にも一致する。
この点は、grep
のようなプログラムでの正規表現の扱い方と対照的である。
バッファのかわりに文字列と一致を取るときには、
`^'は文字列の先頭や改行文字`\n'のうしろに一致する。
バッファのかわりに文字列と一致を取るときには、
`$'は文字列の末尾や改行文字`\n'のまえに一致する。
`\'は特別な文字をクォートするので、 `\$'は文字`$'だけに一致する正規表現、 `\['は文字`['だけに一致する正規表現、 といった具合になる。
`\'にはLisp文字列の入力構文(see String Type)でも
特別な意味があり、`\'でクォートする必要があることに注意してほしい。
たとえば、文字`\'に一致する正規表現は`\\'である。
文字群`\\'を含むLisp文字列を書くには、各`\'をクォートするために
`\'が必要である。
したがって、`\'に一致する正規表現の入力構文は"\\\\"
である。
注意: 従来との互換性のために、 特別な文字がそれらの特別な意味をなしえない文脈で使われた場合には、 普通の文字として扱われる。 たとえば、`*foo'では、`*'の対象となる正規表現が直前にないため、 `*'は普通の文字として扱われる。 このようなふるまいに依存することはよいことではない。 特別な文字は書く位置に関係なくクォートするべきである。
多くの場合、任意の文字を伴う`\'はその文字だけに一致します。 しかし、いくつか例外があって、 `\'で始まる2文字列が特別な意味を持つ場合があります。 (2文字目にくる文字は、 単独で使った場合にはつねに普通の文字として扱われる。) 以下に`\'の構成を示します。
したがって、`foo\|bar'は、`foo'や`bar'に一致するが、 それ以外の文字列には一致しない。
`\|'は、周囲にある適用しうる正規表現の中でも最大のものに適用される。 `\|'によるグループ化を制限するのは、 これを囲む`\( ... \)'によるグループ化だけである。
何度`\|'を使っても処理できるだけの十分なバックトラック能力がある。
最後の使い方は、括弧によるグループ化という考え方から
派生したものではない。
同一の`\( ... \)'構成に与えた2つめの別の機能である。
実用上、これら2つの意味が混同されることはないからである。
この機能をつぎに説明する。
いいかえれば、一致を処理するときには、 `\( ... \)'構成の末尾に達すると、 この構成に一致したテキストの始めと終りを記録する。 そして、正規表現のそれよりうしろでは、 『d番目に現れた`\( ... \)'に一致したテキスト』という意味で それがなんであろうと`\'に続けて数字dを使える。
1つの正規表現内に現れる最初の9個の`\( ... \)'に一致する文字列には、 正規表現中で開き括弧が現れた順に、1から9までの番号を割り振る。 そのため、`\1'から`\9'で、 対応する`\( ... \)'に一致したテキストを参照できる。
たとえば、`\(.*\)\1'は、改行を含まない文字列で、かつ、
前半と後半が同一である文字列に一致する。
`\(.*\)'は前半部分に一致し、それはどのようなものでもかまわない。
一方、それに続く`\1'は、
前半部分とまったく同じテキストに一致しなければならない。
つぎの正規表現は空の文字列に一致します。 つまりこれらは文字を使用しませんが、 これらが一致するかどうか文脈に依存します。
`\b'は、
バッファの先頭や末尾にあるテキストとは無関係に、
バッファの先頭や末尾にも一致する。
任意の文字列が正しい正規表現ではありません。
たとえば、(`[]]'のような少数の例外を除けば)
角括弧が対応していない文字列は正しくありませんし、
1つの`\'で終る文字列も正しくありません。
不正な正規表現を探索関数に渡すと、
エラーinvalid-regexp
が通知されます。
この関数は、stringだけに正確に一致する正規表現の文字列を返す。 これにより、正規表現を必要とする関数を呼び出すときに この文字列だけに正確に一致できる。
(regexp-quote "^The cat$") => "\\^The cat\\$"
regexp-quote
の用途の1つは、 正規表現で記述された文脈に正確に一致する文字列を組み合わせることである。 たとえば、つぎは、白文字で囲まれたstringの値で表される文字列を探索する。(re-search-forward (concat "\\s-" (regexp-quote string) "\\s-"))
この関数は、文字列stringsのいずれかに一致する 効率よい正規表現を返す。 これは、たとえばフォントロック(font-lock)モードなどで、 可能な限り高速な一致や探索を行う必要がある場合に有用である。
省略可能な引数parenが
nil
以外であると、 返される正規表現はつねに少なくとも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)))