[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33. 探索と一致

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Searching%20and%20Matching"
"elisp/探索と一致"へのコメント(無し)
検索全文Elisp

GNU Emacsにはバッファから指定したテキストを探す方法が2つあります。 文字列そのものを正確に探索するのと正規表現の探索です。 正規表現の探索のあとでは、 正規表現全体やそのさまざまな部分に一致したテキストを表す マッチデータ(match data)を調べることができます。

`skip-chars...'などの関数もある種の探索を行います。 See 節 29.2.7 文字群の飛び越し



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.1 文字列の探索

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=String%20Search"
"elisp/文字列の探索"へのコメント(無し)
検索全文Elisp

これらは、バッファ内のテキストを探索するための基本関数です。 これらはプログラムで使うことを意図していますが、 対話的に呼び出すこともできます。 その場合、探索文字列を問い合わせてきますが、 limitnoerrornilに、repeatは1に設定されます。

これらの探索関数は、バッファがマルチバイトであると 探索文字列をマルチバイトに変換します。 バッファがユニバイトであると探索文字列をユニバイトに変換します。 See 節 32.1 テキスト表現

コマンド: search-forward string &optional limit noerror repeat
この関数は、ポイントから前方へ向けて文字列stringに ちょうど一致するものを探す。 それに成功すれば、ポイントをみつけた出現箇所の末尾に移動し、 ポイントの新たな値を返す。 一致がみつからなければ、戻り値と副作用はnoerrorに依存する(下記参照)。

つぎの例では、ポイントは始めは行頭にある。 そして(search-forward "fox")は`fox'の最後の文字のうしろに ポイントを移動する。

 
---------- Buffer: foo ----------
-!-The quick brown fox jumped over the lazy dog.
---------- Buffer: foo ----------

(search-forward "fox")
     => 20

---------- Buffer: foo ----------
The quick brown fox-!- jumped over the lazy dog.
---------- Buffer: foo ----------

引数limitは探索の上限を指定する。 (カレントバッファ内の位置であること。) その位置を越える箇所での一致は受け入れない。 limitを省略したりnilであると、 デフォルトは、バッファの参照可能部分の末尾である。

探索に失敗した場合の動作は、noerrorの値に依存する。 noerrornilであると、 エラーsearch-failedを通知する。 noerrortであると、 search-forwardnilを返しなにもしない。 noerrornilでもtでもないと、 search-forwardはポイントを上限位置へ移動してnilを返す。 (この場合にもポイントの新たな値を返すほうが一貫性があるが、 値nilに依存しているプログラムがある。)

repeatを指定してあると(正の数であること)、 その回数だけ探索を繰り返す(一致箇所の末尾を新たな探索の開始位置とする)。 連続してこれらの探索に成功すると関数は成功し、 ポイントを移動してその新たな値を返す。 さもなければ探索は失敗である。

コマンド: search-backward string &optional limit noerror repeat
この関数は、ポイントから後方へ向けてstringを探索する。 search-forwardと同様であるが、後方へ向けて探索し 一致箇所の先頭にポイントを置く点が異なる。

コマンド: word-search-forward string &optional limit noerror repeat
この関数は、ポイントから前方へ向けてstringに一致する『単語』を探索する。 一致をみつけると、一致箇所の末尾にポイントを設定し ポイントの新たな値を返す。

単語の一致では、stringを単語の列とみなし、 それらを区切る句読点は無視する。 バッファ内の同じ単語の列を探す。 バッファ内の各単語は別々になっている必要があるが (単語`ball'を探索すると単語`balls'には一致しない)、 句読点や空白の詳細は無視される (`ball boy'を探索すると`ball. Boy!'に一致する)。

つぎの例では、ポイントは始めはバッファの先頭にある。 探索するとポイントは`y'と`!'のあいだに移動する。

 
---------- Buffer: foo ----------
-!-He said "Please!  Find
the ball boy!"
---------- Buffer: foo ----------

(word-search-forward "Please find the ball, boy.")
     => 35

---------- Buffer: foo ----------
He said "Please!  Find
the ball boy-!-!"
---------- Buffer: foo ----------

limitnil以外(カレントバッファ内の位置)であると、 それは探索の上限を指定する。 みつかった一致箇所はその位置を越えてはならない。

noerrornilであると、 探索に失敗するとエラーword-search-failedを通知する。 noerrortであると、 エラーを通知するかわりにnilを返す。 noerrornilでもtでもないと、 ポイントをlimit(あるいはバッファの末尾)へ移動してnilを返す。

repeatnil以外であると、 その回数だけ探索を繰り返す。 ポイントは最後の一致箇所の末尾へ置かれる。

コマンド: word-search-backward string &optional limit noerror repeat
この関数はポイントから後方へ向けてstringに一致する単語を探索する。 この関数はword-search-forwardと同様であるが、 後方へ向けて探索し一致箇所の先頭にポイントを置く点が異なる。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.2 正規表現

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Regular%20Expressions"
"elisp/正規表現"へのコメント(無し)
検索全文Elisp

正規表現(regular expression、略してregexp)は、 文字列の(無限の可能性もある)集合を表すパターンです。 正規表現への一致を探すことは、非常に強力な操作です。 本節では、正規表現の書き方を説明します。 続く節では、それらを探索する方法を説明します。

33.2.1 正規表現の構文  Rules for writing regular expressions.
33.2.2 複雑な正規表現の例  Illustrates regular expression syntax.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.2.1 正規表現の構文

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Syntax%20of%20Regexps"
"elisp/正規表現の構文"へのコメント(無し)
検索全文Elisp

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

たとえば、`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 節 32.1 テキスト表現)のバッファや文字列を 探索するときにはうまく働くが、マルチバイトのバッファや文字列では 多くの非ASCII文字のコードは8進数0377より大きいために働かない。 しかし、正規表現`[^\000-\177]'は、 ASCII文字のみを除外しているため、 マルチバイト表現でもユニバイト表現でもすべての非ASCII文字に一致する。

範囲指定の始めと終りは同じ文字集合(see 節 32.5 文字集合)に 属している必要がある。 したがって、`[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 節 2.3.8 文字列型)でも 特別な意味があり、`\'でクォートする必要があることに注意してほしい。 たとえば、文字`\'に一致する正規表現は`\\'である。 文字群`\\'を含む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 節 34. 構文テーブル

`\W'
単語構成文字以外の文字に一致する。

`\scode'
構文コードがcodeである文字だけに一致する。 ここで、codeは構文コードを表す文字である。 つまり、`w'は単語構成要素を、 `-'は白文字を、`('は開き括弧を表すといった具合である。 白文字の構文を表すには、`-'か空白のいずれかを使う。 構文コードとそれらを表す文字の一覧については、 see 節 34.2.1 構文クラス一覧

`\Scode'
構文がcodeでない任意の文字に一致する。

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

`\`'
空の文字列に一致するが、 一致対象であるバッファや文字列の先頭に限る。

`\''
空の文字列に一致するが、 一致対象であるバッファや文字列の末尾に限る。

`\='
空の文字列に一致するが、ポイント位置に限る。 (文字列に対する一致ではこの構文は定義されない。)

`\b'
空の文字列に一致するが、単語の先頭や末尾に限る。 したがって、`\bfoo\b'は、単語として独立して現れる`foo'に一致する。 `\bballs?\b'は、単語として独立して現れる `ball'や`balls'に一致する。

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

`\B'
空の文字列に一致するが、単語の先頭や末尾以外に限る。

`\<'
空の文字列に一致するが、単語の先頭に限る。 `\<'はバッファの先頭にも一致するが、単語構成文字が続く場合に限る。

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

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

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

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

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

 
(re-search-forward
 (concat "\\s-" (regexp-quote string) "\\s-"))

Function: 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)))

Function: regexp-opt-depth regexp
この関数は、var{regexp}内のグループ化構文(括弧で括った式)の 総個数を返す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.2.2 複雑な正規表現の例

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Regexp%20Example"
"elisp/複雑な正規表現の例"へのコメント(無し)
検索全文Elisp

ここでは、任意個数の白文字を伴った文末を認識するために Emacsで使われている複雑な正規表現について述べます。 それは変数sentence-endの値です。

まず、タブ文字と空白を区別するためにLisp構文の文字列として 正規表現を示します。 文字列定数はダブルクォートで始まり終ります。 `\"'は文字列の一部としてのダブルクォート、 `\\'は文字列の一部としてのバックスラッシュ、 `\t'はタブ、`\n'は改行を表します。

 
"[.?!][]\"')}]*\\($\\| $\\|\t\\|  \\)[ \t\n]*"

対照的に、変数sentence-endを評価するとつぎのように なっているはずです。

 
sentence-end
     => "[.?!][]\"')}]*\\($\\| $\\|  \\|  \\)[       
]*"

この出力では、タブと改行はそれ自身として現れています。

この正規表現には、連続してつぎのような4つの部分が含まれています。

[.?!]
パターンの最初の部分は、3つの文字、ピリオド、疑問符、感嘆符の いずれかに一致する文字選択である。 一致部分はこれらの3つの文字の1つで始まる必要がある。

[]\"')}]*
パターンの2番目の部分は、ピリオド、疑問符、感嘆符のいずれかに続く、 任意の閉じ括弧やクォーテーションマークの0個以上の繰り返しに一致する。 \"は、文字列内のダブルクォートを表すLisp構文である。 最後の`*'は、直前の正規表現(この場合は文字選択)を 0回以上繰り返すことを表す。

\\($\\| $\\|\t\\| \\)
パターンの3番目の部分は、文末に続く白文字、 つまり、(空白を伴うかもしれない)行末、1つのタブ、2つの空白の いずれかに一致する。 2つのバックスラッシュは、括弧や縦棒を正規表現の構文にする。 括弧はグループを区切り、縦棒は選択肢を区切る。 ドル記号は行末に一致するために用いている。

[ \t\n]*
パターンの最後の部分は、 文末に最低限必要な白文字より余計な白文字に一致する。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.3 正規表現の探索

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Regexp%20Search"
"elisp/正規表現の探索"へのコメント(無し)
検索全文Elisp

GNU Emacsでは、正規表現に一致するつぎの部分を インクリメンタルにもそうでなくも探せます。 インクリメンタルサーチコマンドについては、 節 `正規表現探索' in

GNU Emacs マニュアル
を 参照してください。 ここでは、プログラムで有用な探索関数のみについて述べます。 基本的なものはre-search-forwardです。

これらの探索関数は、バッファがマルチバイトであれば 正規表現をマルチバイトに変換します。 バッファがユニバイトであれば、正規表現をユニバイトに変換します。 See 節 32.1 テキスト表現

コマンド: re-search-forward regexp &optional limit noerror repeat
この関数は、カレントバッファにおいて前方へ向けて 正規表現regexpに一致するテキストの文字列を探索する。 関数はregexpに一致しないテキストはすべて飛び越え、 みつけた一致箇所の末尾へポイントを置く。 ポイントの新たな値を返す。

limitnil以外(カレントバッファ内の位置であること)であると、 探索の上限を表す。 その位置を越える箇所での一致は受け入れない。

repeatを指定してあると(正の数であること)、 その回数だけ探索を繰り返す(一致箇所の末尾を新たな探索の開始位置とする)。 連続してこれらの探索に成功すると関数は成功し、 ポイントを移動してその新たな値を返す。 さもなければ探索は失敗である。

関数が失敗した場合の動作は、noerrorの値に依存する。 noerrornilであると、 エラーsearch-failedを通知する。 noerrortであると、 re-search-forwardはなにもせずにnilを返す。 noerrornilでもtでもないと、 re-search-forwardはポイントをlimit(あるいはバッファの末尾)へ 移動してnilを返す。

つぎの例では、ポイントは始めは`T'のまえにある。 探索を呼び出すと、ポイントは当該行の末尾 (`hat'の`t'と改行のあいだ)へ移動する。

 
---------- Buffer: foo ----------
I read "-!-The cat in the hat
comes back" twice.
---------- Buffer: foo ----------

(re-search-forward "[a-z]+" nil t 5)
     => 27

---------- Buffer: foo ----------
I read "The cat in the hat-!-
comes back" twice.
---------- Buffer: foo ----------

コマンド: re-search-backward regexp &optional limit noerror repeat
この関数は、カレントバッファにおいて後方へ向けて 正規表現regexpに一致するテキストの文字列を探索し、 みつけた一致箇所の先頭へポイントを置く。

この関数はre-search-forwardに類似したものであるが、 単純な鏡像ではない。 re-search-forwardは、一致箇所の先頭が 開始位置に可能な限り近い一致箇所を探す。 re-search-backwardが完全な鏡像であれば、 一致箇所の末尾が可能な限り近い一致箇所を探す。 しかし、実際には、一致箇所の先頭が可能な限り近い一致箇所を探す。 これは、正規表現との一致をとる処理は、 指定開始位置において先頭から末尾へ向けてつねに行われるからである。

re-search-forwardの完全な鏡像には、 正規表現の一致を末尾から先頭へ向けて行う特別な機能が必要である。 それを実装する手間をかけるほどの価値はない。

Function: string-match regexp string &optional start
この関数は、文字列stringにおいて正規表現regexpに一致した 最初の箇所の添字を返す。 あるいは、一致がなければnilを返す。 startnil以外であると、 stringの指定した添字から探索を始める。

たとえばつぎのとおりである。

 
(string-match
 "quick" "The quick brown fox jumped quickly.")
     => 4
(string-match
 "quick" "The quick brown fox jumped quickly." 8)
     => 27

文字列の最初の文字の添字は0であり、 2番目の文字の添字は1であるといった具合になる。

この関数から戻ったあとでは、 一致箇所を越えた最初の文字の添字は(match-end 0)で得られる。 see 節 33.6 マッチデータ

 
(string-match
 "quick" "The quick brown fox jumped quickly." 8)
     => 27

(match-end 0)
     => 32

Function: looking-at regexp
この関数は、カレントバッファ内のポイントの直後のテキストが 正規表現regexpに一致するかどうかを調べる。 ここで『直後』とは、開始位置は固定されていて、 ポイントのうしろの最初の文字で始まる場合にのみ探索は成功する。 結果は、一致すればtであり、さもなければnilである。

この関数はポイントを移動しないが、マッチデータを更新する。 match-beginningmatch-endを使ってマッチデータを参照できる。

つぎの例では、ポイントは`T'の直前にある。 ポイントがこれ以外の場所にあると結果はnilになる。

 
---------- Buffer: foo ----------
I read "-!-The cat in the hat
comes back" twice.
---------- Buffer: foo ----------

(looking-at "The cat in the hat$")
     => t



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.4 POSIXの正規表現探索

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=POSIX%20Regexps"
"elisp/POSIXの正規表現探索"へのコメント(無し)
検索全文Elisp

普通の正規表現関数は、`\|'や反復構文を扱うために必要なときには バックトラックしますが、これを行い続けるのは なんらかの一致をみつけるまでです。 みつけてしまえば、それらは成功してみつけた最初の一致を報告します。

本節では、正規表現の一致に関するPOSIX規格で規定された 完全なバックトラックを行う代替の探索関数について述べます。 それらはすべての可能性を試し尽くしすべての一致箇所を探し終える までバックトラックを継続してます。 そのため、POSIXで要求されるとおりの最長の一致を報告できるのです。 これは動作がとても遅いですから、最長一致が本当に必要な場合に限って これらの関数を使ってください。

Function: posix-search-forward regexp &optional limit noerror repeat
これはre-search-forwardと同様であるが、 正規表現の一致に関するPOSIX規格で規定された完全なバックトラックを行う。

Function: posix-search-backward regexp &optional limit noerror repeat
これはre-search-backwardと同様であるが、 正規表現の一致に関するPOSIX規格で規定された完全なバックトラックを行う。

Function: posix-looking-at regexp
これはlooking-atと同様であるが、 正規表現の一致に関するPOSIX規格で規定された完全なバックトラックを行う。

Function: posix-string-match regexp string &optional start
これはstring-matchと同様であるが、 正規表現の一致に関するPOSIX規格で規定された完全なバックトラックを行う。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.5 探索と置換

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Search%20and%20Replace"
"elisp/探索と置換"へのコメント(無し)
検索全文Elisp

Function: perform-replace from-string replacements query-flag regexp-flag delimited-flag &optional repeat-count map
この関数は、query-replaceと関連するコマンドの中身である。 from-stringの出現を探しだし、それらの一部やすべてを置き換える。 query-flagnilであると、すべての出現を置換する。 さもなければ、1つ1つユーザーにどうするかを問い合わせる。

regexp-flagnil以外であると、 from-stringを正規表現として扱う。 さもなければ、その字面とおりに一致する。 delimited-flagnil以外であると、 単語区切りで囲まれたもののみを対象にする。

引数replacementsは、出現を置き換えるものを指定する。 それが文字列であれば、その文字列を使う。 文字列のリストでもよく、要素を巡回して使う。

repeat-countnil以外であれば、整数であること。 これは、replacementsのリスト内の各文字列を つぎに進めるまえに何回使用するかを指定する。

通常、キーマップquery-replace-mapで、 可能なユーザーの応答を定義する。 引数mapnil以外であれば、 query-replace-mapのかわりに使うキーマップである。

Variable: query-replace-map
この変数は、y-or-n-pmap-y-or-n-pに加えて、 query-replaceや関連する関数に対する 正しいユーザー応答を定義する特別なキーマップを保持する。 2つの意味で普通のものではない。

query-replace-map向けの意味のある『バインディング』をつぎに示します。 query-replaceと関連するものだけに意味のあるものもあります。

act
当該動作を行う、いいかえれば『yes』。

skip
この問いに対する動作は行わない、いいかえれば『no』。

exit
この問いには『no』で答え、 残りの応答も『no』と仮定して一連の問いを止める。

act-and-exit
この問いには『yes』で答え、 残りの応答は『no』と仮定して一連の問いを止める。

act-and-show
この問いには『yes』で答えるが、結果を表示する。 つぎの問いへは進まない。

automatic
この問いと以降の一連の問いに『yes』で答え、 これ以降ユーザーに問い合わせない。

backup
問いに答えたまえの箇所へ戻る。

edit
この問いに対処するために、通常の動作のかわりに再帰編集に入る。

delete-and-edit
対象のテキストを削除してから、 それを置き換えるために再帰編集に入る。

recenter
ウィンドウの中央に位置決めして再表示してから、 同じ問いを問い直す。

quit
ただちに中断する。 y-or-n-pと関連する関数でのみ、この応答を用いる。

help
ヘルプを表示してから、再度問い直す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.6 マッチデータ

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Match%20Data"
"elisp/マッチデータ"へのコメント(無し)
検索全文Elisp

Emacsは、正規表現の探索中に捜し出したテキスト断片の開始/終了位置を 記録しています。 つまり、たとえば、rmailメッセージ内で日付のような複雑なパターンを 探索してから、パターンの制御をもとに一致した一部分を取り出せるのです。

マッチデータは、通常、もっとも最近に行った探索のみを記述するので、 あとで使用したい探索とそのマッチデータを使うあいだに、 不注意に別の探索を行わないように注意してください。 あいだで探索を行う必要がある場合には、その周りで マッチデータを保存/復元してそれらが上書きされないようにします。

33.6.1 一致したテキストの置換  Replacing a substring that was matched.
33.6.2 マッチデータの簡単な参照  Accessing single items of match data, such as where a particular subexpression started.
33.6.3 マッチデータ全体を参照する  Accessing the entire match data at once, as a list.
33.6.4 マッチデータの保存と復元  Saving and restoring the match data.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.6.1 一致したテキストの置換

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Replacing%20Match"
"elisp/一致したテキストの置換"へのコメント(無し)
検索全文Elisp

この関数は、最後の探索で一致したテキストをreplacementで置換します。

Function: replace-match replacement &optional fixedcase literal string subexp
この関数は、最後の探索で一致したバッファ内(あるいは文字列string)の テキストを置換する。 当該テキストをreplacementで置き換える。

バッファで最後に探索を行った場合には、 stringnilを指定すること。 そうすると、replace-matchはバッファを編集することで置換を行い、 置換したテキストの末尾にポイントを置きtを返す。

文字列で探索した場合には、stringに同じ文字列を渡すこと。 そうすると、replace-matchは新たな文字列を構築することで 置換を行い、新たな文字列を返す。

fixedcasenil以外であると、 置換テキストの大文字小文字は変更しない。 さもなければ、置換テキストの大文字小文字は、 対象テキストの大文字小文字に応じて変換される。 元テキストがすべて大文字であると、置換テキストも大文字に変換される。 元テキストの最初の単語が大文字で始まっていると、 置換テキストの最初の単語も大文字で始める。 元テキストが1単語のみであり、しかも、その単語が大文字1文字であると、 replace-matchはすべてが大文字ではなく大文字で始まるとみなす。

case-replacenilであると、 fixed-caseの値に関わらず、大文字小文字変換を行わない。 see 節 33.7 探索と大文字小文字

literalnil以外であると、 必要に応じて大文字小文字変換は行うものの replacementをそのまま挿入する。 それがnil(デフォルト)であると、 文字`\'を特別に扱う。 replacementに`\'が現れるときには、 つぎの列のいずれかであること。

`\&'
`\&'は置換対象のテキスト全体を表す。

`\n'
nを数字文字とすると`\n'は、 もとの正規表現内のn番目の部分式に一致したテキストを表す。 部分式とは、`\(...\)'で囲んでグループ化した式である。

`\\'
`\\'は置換テキスト内で1つの`\'を表す。

subexpnil以外であると、 一致箇所全体ではなく正規表現のsubexp番目の部分式に 一致した箇所のみを置換することを指示する。 たとえば、`foo \(ba*r\)'に一致させたあとで、 subexpに1を指定してreplace-matchを呼び出すと、 `\(ba*r\)'に一致したテキストのみを置換することを意味する。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.6.2 マッチデータの簡単な参照

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Simple%20Match%20Data"
"elisp/マッチデータの簡単な参照"へのコメント(無し)
検索全文Elisp

本節では、最後の探索や一致操作において なにに一致したのかを調べるためのマッチデータの使い方を説明します。

一致したテキスト全体や正規表現の括弧で括った特定の部分式に一致した テキストを調べることができます。 以下の関数の引数countでどれかを指定します。 countがゼロであれば、一致全体を調べることになります。 countが正であれば、望みの部分式を指定します。

正規表現の部分式は、エスケープした括弧`\(...\)'でグループ化した 式であることに注意してください。 count番目の部分式は、正規表現全体の先頭から `\('の出現を数えてみつけます。 最初の部分式は1、つぎは2、といった具合です。 部分式は正規表現だけにあります。 単純な文字列探索のあとでは、利用可能な情報は一致全体に関するものだけです。

探索に失敗すると、マッチデータを変更することもしないこともあります。 過去には探索に失敗しても変更しなかったのですが、 将来そうなります。

Function: match-string count &optional in-string
この関数は、最後の探索や一致操作で一致したテキストを文字列として返す。 countがゼロであるとテキスト全体を返す。 countが正であれば、count番目の括弧で囲んだ部分式に対応する 部分のみを返す。 countが範囲を越えていたり、当該部分式に一致するものがない場合には、 値はnilである。

最後の探索や一致操作をstring-matchで文字列に対して行った場合には、 引数in-stringとして同じ文字列を渡すこと。 バッファの探索や一致のあとでは、in-stringを省略するか nilを渡すこと。 ただし、match-stringを呼び出すときのカレントバッファが 探索を行ったときのバッファであること。

Function: match-string-no-properties count
この関数はmatch-stringと同様であるが、 結果にはテキスト属性を含まない。

Function: match-beginning count
この関数は、最後の正規表現探索やその部分式に一致したテキストの開始位置を返す。

countがゼロであると、値は一致全体の開始位置である。 さもなければ、countは正規表現内の部分式を指定し、 関数の値は当該部分式に一致した部分の開始位置である。

一致に利用されなかった選択肢`\|'内の部分式に対しては、 値はnilである。

Function: match-end count
この関数はmatch-beginningと同様であるが、 一致箇所の開始位置ではなく終了位置を返す点が異なる。

コメントでテキスト内の位置を示しながら マッチデータの利用例を示します。

 
(string-match "\\(qu\\)\\(ick\\)"
              "The quick fox jumped quickly.")
              ;0123456789      
     => 4

(match-string 0 "The quick fox jumped quickly.")
     => "quick"
(match-string 1 "The quick fox jumped quickly.")
     => "qu"
(match-string 2 "The quick fox jumped quickly.")
     => "ick"

(match-beginning 1)       ; 一致箇所`qu'の先頭は
     => 4                 ;   添字4

(match-beginning 2)       ; 一致箇所`ick'の先頭は
     => 6                 ;   添字6

(match-end 1)             ; 一致箇所`qu'の末尾は
     => 6                 ;   添字6

(match-end 2)             ; 一致箇所`ick'の末尾は
     => 9                 ;   添字9

別の例も示します。 ポイントは始めは行頭にあります。 探索によって、ポイントは空白と単語`in'のあいだに移動します。 一致箇所全体の先頭はバッファの9番目の文字(`T')であり、 最初の部分式の一致箇所の先頭は13番目の文字(`c')です。

 
(list
  (re-search-forward "The \\(cat \\)")
  (match-beginning 0)
  (match-beginning 1))
    => (9 9 13)

---------- Buffer: foo ----------
I read "The cat -!-in the hat comes back" twice.
        ^   ^
        9  13
---------- Buffer: foo ----------

(この例では、返される添字はバッファ内位置であり、 バッファの最初の文字を1と数える。)



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.6.3 マッチデータ全体を参照する

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Entire%20Match%20Data"
"elisp/マッチデータ全体を参照する"へのコメント(無し)
検索全文Elisp

関数match-dataset-match-dataは、 マッチデータ全体を一度に読んだり書いたりします。

Function: match-data
この関数は、最後の探索で一致したテキストに関するすべての情報を収めた 新たに構築したリストを返す。 要素0が式全体に一致した部分の先頭位置であり、 要素1が式全体に一致した部分の終了位置である。 つぎの2つの要素は最初の部分式に一致した部分の先頭/終了位置、 といった具合である。 一般に、要素 番号2n(match-beginning n)に対応し、 要素 番号2n + 1 は(match-end n)に対応する。

バッファで行った一致ではすべての要素はマーカかnilであり、 string-matchにより文字列で行った一致では すべての要素は整数かnilである。

探索関数の呼び出しとその探索結果としてのマッチデータを参照するための match-dataの呼び出しのあいだには、 別の探索があってはならない。

 
(match-data)
     =>  (#<marker at 9 in foo>
          #<marker at 17 in foo>
          #<marker at 13 in foo>
          #<marker at 17 in foo>)

Function: set-match-data match-list
この関数は、match-listの要素からマッチデータを設定する。 match-listは、以前にmatch-dataの呼び出しで得たリストであること。

match-listが存在しないバッファを指していても、エラーにはならない。 無意味な情報をマッチデータに設定するが、害にはならない。

store-match-dataはほぼ廃れているset-match-dataの別名である。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.6.4 マッチデータの保存と復元

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Saving%20Match%20Data"
"elisp/マッチデータの保存と復元"へのコメント(無し)
検索全文Elisp

探索を行う可能性がある関数を呼び出す場合、 あとで使うためにそれ以前の探索によるマッチデータを保存したいときには、 当該関数の呼び出しの周りでマッチデータを保存し復元する必要があります。 つぎの例は、マッチデータを保存し損なった場合に生じる問題点を 示しています。

 
(re-search-forward "The \\(cat \\)")
     => 48
(foo)                   ; fooはさらに
                        ;   探索する
(match-end 0)
     => 61              ; 予期しない結果。48でない!

マッチデータの保存と復元はsave-match-dataで行えます。

Macro: save-match-data body...
このマクロは、周りのマッチデータを保存し復元して、 bodyを実行する。

スペシャルフォームsave-match-dataの効果をまねるために match-dataとともにset-match-dataを使うこともできます。 つぎのようにします。

 
(let ((data (match-data)))
  (unwind-protect
      ...   ; もとのマッチデータを変更しても大丈夫
    (set-match-data data)))

プロセスフィルタ関数(see 節 36.9.2 プロセスフィルタ関数)や プロセスの番兵(see 節 36.10 番兵:プロセスの状態変化の検出)を実行するときには、 Emacsは自動的にマッチデータを保存し復元します。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.7 探索と大文字小文字

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Searching%20and%20Case"
"elisp/探索と大文字小文字"へのコメント(無し)
検索全文Elisp

デフォルトでは、Emacsの探索は探索対象テキストの大文字小文字を区別しません。 `FOO'を探す指定を行うと、 `Foo'や`foo'にも一致するとみなします。 これは、正規表現にも適用されます。 したがって、`[aB]'は、`a'や`A'や`b'や`B'に一致します。

この機能を望まないときには、 変数case-fold-searchnilを設定します。 すると、すべての文字は大文字小文字を保ってそのとおりに一致します。 これはバッファローカルな変数ですから、 変数を変更してもカレントバッファだけに影響します。 (see 節 10.10.1 バッファローカルな変数の紹介。) あるいは、default-case-fold-searchの値を変更します。 これは、case-fold-searchを書き変えていないバッファ向けの デフォルト値です。

ユーザーレベルのインクリメンタルサーチ機能では、 大文字小文字の区別は異なった扱い方をします。 小英文字を与えるとその大文字にも一致しますが、 大英文字を与えると大文字のみに一致します。 しかし、これはLispコードで使用している探索関数には まったく関係ありません。

User Option: case-replace
この変数は、置換関数が大文字小文字を保存するかどうかを決定する。 変数がnilであると、置換テキストをそのまま使うことを意味する。 nil以外の値であると、置換対象のテキストに応じて 置換テキストの大文字小文字を変換することを意味する。

この変数が実際に効果を発揮するのは関数replace-matchにおいてである。 see 節 33.6.1 一致したテキストの置換

User Option: case-fold-search
このバッファローカルな変数は、 大文字小文字を区別して探索するかどうかを決定する。 変数がnilであると大文字小文字を区別する。 さもなければ大文字小文字を区別しない。

Variable: default-case-fold-search
この変数の値は、case-fold-searchを書き変えていないバッファ向けの デフォルト値である。 これは(default-value 'case-fold-search)と同じである。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

33.8 編集に用いられる標準的な正規表現

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Standard%20Regexps"
"elisp/編集に用いられる標準的な正規表現"へのコメント(無し)
検索全文Elisp

本節では、編集上の特定目的に用いられる正規表現を保持している 変数について述べます。

Variable: page-delimiter
これは、ページを区切る行頭を記述した正規表現である。 デフォルト値は、"^\014"(つまり、"^^L"すなわち"^\C-l") である。 これはページ送り文字で始まる行に一致する。

つぎの2つの正規表現は、つねに行の先頭から一致が 始まると仮定してはいけません。 一致の開始位置を固定する`^'を使うべきではありません。 ほとんどの場合、段落コマンドは行の先頭でのみ一致を検査しますから、 `^'は不必要であることを意味します。 幅0以外の左端余白があると、段落コマンドは左端余白のうしろからの一致を 受け入れます。 そのような場合、`^'は誤りです。 しかし、左端余白をけっして使わないモードならば、 `^'は無害です。

Variable: paragraph-separate
これは、段落を区切る行の始まりを認識するための正規表現である。 (これを変更したら、paragraph-startも変更すること。) デフォルト値は"[ \t\f]*$"であり、 (左端余白に続く)空白やタブやページ送りだけから成る行に一致する。

Variable: paragraph-start
これは、段落を始める行や区切る行の始まりを認識するための正規表現である。 デフォルト値は"[ \t\n\f]"であり、 (左端余白に続く)空白やタブやページ送りだけから成る行に一致する。

Variable: sentence-end
これは、文末を記述する正規表現である。 (これに関わらず、段落の区切りも文末である。) デフォルト値はつぎのとおりである。

 
"[.?!][]\"')}]*\\($\\| $\\|\t\\| \\)[ \t\n]*"

これは、ピリオド、疑問符、感嘆符のいずれかのあとに 閉じ括弧文字が続き(なくてもよい)、 タブや空白や改行が続くことを意味する。

この正規表現の詳しい説明は、33.2.2 複雑な正規表現の例を参照。


[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端] [?]