[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.11 正規表現

GaucheはPOSIXの拡張正規表現にほぼ上位互換な正規表現エンジンを 組込みで持っています。また、Perl 5の正規表現からいくつかの 拡張機能を採り入れています。

Builtin Class: <regexp>

正規表現オブジェクトのクラスです。string->regexpを使って実行時に 作成できます。また、Gaucheはリテラルの正規表現を表す構文を持っており、 ロード時に作成することもできます。

Gaucheの正規表現エンジンはマルチバイト文字列に対応しています。

Builtin Class: <regmatch>

正規表現マッチオブジェクトのクラスです。正規表現エンジンrxmatchは、 一致した場合にこのオブジェクトを返します。部分一致の情報を含めた 全てのマッチに関する情報がこのオブジェクトに含まれています。

一致した部分文字列やそのインデックスのリストではなく マッチオブジェクトを返すことの利点は効率です。 regmatchオブジェクトはマッチの内部状態を保持しており、 要求された時にはじめて該当する部分文字列やインデックスを計算します。 これは特にマルチバイト文字列に有効です。マルチバイト文字列 へのインデックスアクセスは遅いからです。

Reader Syntax: #/regexp-spec/
Reader Syntax: #/regexp-spec/i

リテラルの正規表現オブジェクトを表記します。読まれた際に<regexp>の インスタンスとなります。

末尾に文字iが与えられた場合は、マッチ時に大文字小文字を区別しない 正規表現オブジェクトとなります。(現在のバージョンでは、大文字小文字の 同一視はASCII文字のみに対して行われます。それ以外の文字は通常の方法でマッチします)。

string->regexpに対してこの構文を使う利点は、 正規表現のコンパイルが一度しか行われない点です。この構文は、 内部ループの中でも、正規表現のコンパイルのオーバヘッドを気にせずに 使うことができます。動的に正規表現を作成したい場合のみstring->regexpを 使って下さい。

Gaucheの組み込み正規表現構文はPOSIX拡張正規表現に準じたものに、 Perlの拡張の一部を採り入れたものです。

ここに示す構文は表面的な構文にすぎないことに注意して下さい。 Gaucheの正規表現コンパイラは抽象構文木を扱うようになっており、 将来はSREのような別の構文もサポートされる予定です。

re*

reの0回以上の繰り返しにマッチします。

re+

reの1回以上の繰り返しにマッチします。

re?

reの0回または1回の出現にマッチします。

re{n}
re{n,}
re{n,m}

回数に範囲のある繰り返しです。 re{n}ren回の繰り返しにマッチします。 re{n,}ren回以上の繰り返しにマッチします。 re{n,m}ren回以上、m回以下の 繰り返しにマッチします。但しn <= mとします。

re*?
re+?
re??
re{n,}?
re{n,m}?

上記の繰り返し構造とほぼ同じですが、これらの構文は「non-greedy」または 「lazy」と呼ばれるマッチ戦略を用います。すなわち、まずreがマッチする 最小の回数を試し、それが失敗したら順に繰り返しの回数を増やしてゆきます。 次の例を比べてみてください:

 
(rxmatch-substring (#/<.*>/ "<tag1><tag2><tag3>") 0)
  ⇒ "<tag1><tag2><tag3>"

(rxmatch-substring (#/<.*?>/ "<tag1><tag2><tag3>") 0)
  ⇒ "<tag1>"
(re…)

捕捉とクラスタリング。括弧でくくられた正規表現の列がグループとして 扱われ、またそれにマッチした文字列はサブマッチとして保存されます。

(?:re…)

捕捉無しクラスタリング。reはグループとして 扱われますが、サブマッチとして保存されません。

(?<name>re…)

名前つきの捕捉とクラスタリング。(re…)と同様ですが、 マッチした文字列に名前nameがつけられます。マッチした文字列には インデックスの数字と名前のどちらでも参照できます。

同じ名前が複数回正規表現内に出現した場合、どの名前付き捕捉にマッチした 部分文字列が返されるかは不定です。

(?i:re…)
(?-i:re…)

大文字小文字の区別の制御。 (?i:re…)re…が大文字小文字にかかわらず マッチするようにします。 (?-i:re…)はその逆です。

Perlの正規表現では'?'と':'の間に他のいくつかのフラグを使うことが できますが、Gaucheでは今のところこのフラグのみをサポートしています。

pattern1|pattern2|…

パターンのいずれかにマッチします。

\n

バックリファレンス。nは整数です。 n番目(1から数える)の補捉カッコに補捉された文字列と一致する場合に、\nが マッチします。補足カッコがネストしている場合、開きカッコの順番で数えます。 n番目のカッコが繰り返しの中にあり、複数回マッチ している場合は、最後にマッチした文字列との比較が行われます。

\k<name>

名前によるバックリファレンス。 名前nameを持つ補捉カッコで補捉された文字列と一致する場合に、 \k<name>がマッチします。参照しているカッコが繰り返しの中にあり、 複数回マッチしている場合は、最後にマッチした文字列との比較が行わ れます。同じ名前nameを持つ補捉カッコが複数ある場合には、 それらのカッコの最後にマッチした文字列のいずれかと一致する場合、 マッチが成功します。

.

任意の1文字にマッチします。改行文字にもマッチします。

[char-set-spec]

char-set-specで指定される文字セット内の文字にマッチします。 char-set-specについては文字集合を参照して下さい。

\s, \d, \w

それぞれ空白文字(#[[:space:]])、 数字(#[[:digit:]])、 単語を構成する文字(#[[:alpha:][:digit:]_])にマッチします。

文字セット内でも、その外でも使えます。

\S, \D, \W

それぞれ\s\d\wで指定される文字セットの補集合の 文字にマッチします。

^, $

それぞれ、パターンの最初または最後に指定された場合、 文字列の最初か最後にマッチします。

\b, \B

\bは単語の境界の空文字列にマッチします。 \Bはその逆です。

\;
\"
\#

これらはそれぞれ;"、および#と同じです。 Emacs等、Scheme構文を理解するエディタを混乱させないために使うことができます。

(?=pattern)
(?!pattern)

肯定および否定の先読み。 patternが文字列の現在の位置にマッチする(あるいはマッチ しない)ときにマッチが成功しますが、現在の位置は変更しない ので、後に続く正規表現は現在と同じ位置から適用されます。

例えば、次の表現は、電話番号のうち日本の番号("81"から始まるもの) を除く文字列にマッチします。

 
\+(?!81)\d{9,}
(?<=pattern)
(?<!pattern)

肯定の後読みおよび否定の後読み。 現在の位置の左側にpatternにマッチする文字列がある場合に マッチが成功(あるいは失敗)します。先読みと同様、現在の位置は 変更しません。

内部的にこの表現は、patternを逆転させたうえで、現在の位置 から左に向かってマッチを進めることで実現されています。したがって、 patternには任意のものにマッチする表現を含めることができますが、 マッチの順番や長さが重要な場合(例えば2通りにマッチしうる捕捉の カッコ)などは、左から右に現在位置が進むときとは異なる場所に マッチするかもしれません。

(?>pattern)

アトミックなクラスタリング。patternがいったんマッチすると、その後 patternの中でバックトラックを行いません。

re*+
re++
re?+

それぞれ(?>re*)、(?>re+)、(?>re?)と同じです。

Function: string->regexp string &keyword case-fold

文字列stringを正規表現とみなして、<regexp>のインスタンスを 作成して返します。

キーワード引数case-foldに真の値が与えられた場合、作成される正規表現は 大文字小文字を区別しないものとなります。 (大文字小文字を区別しない正規表現に関しては上の説明を参照して下さい)。

Function: regexp? obj

objが正規表現オブジェクトなら真の値を返します。

Function: regexp->string regexp

正規表現regexpを記述する元になった文字列を返します。 返される文字列は変更不可な文字列です。

Function: rxmatch regexp string

正規表現オブジェクトregexpに一致するものを文字列stringから 探します。一致が見付かった場合は<regmatch>オブジェクトを返し、 見付からなかった場合は#fを返します。

他のScheme処理系ではこれは matchregexp-searchstring-matchなど 様々な名で呼ばれています。

Generic application: regexp string

正規表現オブジェクトは直接文字列に対して適用することもできます。 これは(rxmatch regexp string)と同じ動作をしますが、 表記が短くて済みます。この機能は適用可能なオブジェクト で述べているメカニズムを 使って実装されています。

Function: rxmatch-start match &optional (i 0)
Function: rxmatch-end match &optional (i 0)
Function: rxmatch-substring match &optional (i 0)

rxmatchが返すマッチオブジェクトmatchから情報を取り出します。 iが省略されるか0の場合、これらの手続きはそれぞれ一致した 文字列の開始インデックス、終了インデックス、および一致した部分文字列を 返します。iに正の整数が与えられた場合は、i番目のサブマッチ に関する情報を返します。iにシンボルが与えられた場合は、名前 iを持つサブマッチの情報を返します。同じ名前iを持つ複数の サブマッチがある場合には、成功したサブマッチの情報を返します。 iにそれ以外の値を与えるのはエラーです。

簡便のために、match#fを渡すことも許されています。 その場合、これらの手続きは#fを返します。

これらの手続きはScshでmatch:startmatch:endmatch:substringと呼ばれているものと等価です。

Function: rxmatch-num-matches match

matchの持つマッチの数を返します。この数には 「マッチ全体」も含まれるので、<regmatch>オブジェクトに対しては 常に正の整数が返ることになります。また、値を持たないマッチもカウントされます (下の例を参照)。

簡便のために、match#fを渡すこともできます。 その場合は0が返ります。

 
(rxmatch-num-matches (rxmatch #/abc/ "abc"))
  ⇒ 1

(rxmatch-num-matches (rxmatch #/(a(.))|(b(.))/ "ba"))
  ⇒ 5

(rxmatch-num-matches #f)
  ⇒ 0
Function: rxmatch-after match &optional (i 0)
Function: rxmatch-before match &optional (i 0)

マッチオブジェクトmatchの前および後の文字列を返します。 正の整数がiに与えられた場合はi番目のサブマッチの前および後の 文字列を返します。シンボルが与えられた場合は、その名前を持つ サブマッチの前後の文字列を返します。

 
(define match (rxmatch #/(\d+)\.(\d+)/ "pi=3.14..."))

(rxmatch-after match) ⇒ "..."
(rxmatch-after match 1) ⇒ ".14..."

(rxmatch-before match) ⇒ "pi="
(rxmatch-before match 2) ⇒ "pi=3."
Function: rxmatch->string regexp string &optional selector …

A convenience procedure to match a string to the given regexp, then returns the matched substring, or #f if it doesn't match.

If no selector is given, it is the same as this:

 
(rxmatch-substring (rxmatch regexp string))

If an integer is given as a selector, it returns the subtring of the numbered submatch.

If a symbol after or before is given, it returns the substring after or before the match. You can give these symbols and an integer to extract a substring before or after the numbered submatch.

 
gosh> (rxmatch->string #/\d+/ "foo314bar")
"314"
gosh> (rxmatch->string #/(\w+)@([\w.]+)/ "foo@example.com" 2)
"example.com"
gosh> (rxmatch->string #/(\w+)@([\w.]+)/ "foo@example.com" 'before 2)
"foo@"
Generic application: regmatch &optional index
Generic application: regmatch 'before &optional index
Generic application: regmatch 'after &optional index

マッチオブジェクトは直接整数のインデックスもしくはシンボルに対して適用することが できます。整数に適用したときは(rxmatch-substring regmatch index)、 シンボルbeforeのときは(rxmatch-before regmatch)、シンボル afterのときは(rxmatch-after regmatch)、そのほかのシンボルのときは (rxmatch-substring regmatch symbol)と同じ動作をします。

表記が短くて済みます。 この機能は適用可能なオブジェクト で述べているメカニズムを使って実装されています。

 
(define match (#/(\d+)\.(\d+)/ "pi=3.14..."))

  (match)           ⇒ "3.14"
  (match 1)         ⇒ "3"
  (match 2)         ⇒ "14"

  (match 'after)    ⇒ "..."
  (match 'after 1)  ⇒ ".14..."

  (match 'before)   ⇒ "pi="
  (match 'before 2) ⇒ "pi=3."

(define match (#/(?<integer>\d+)\.(?<fraction>\d+)/ "pi=3.14..."))

  (match 1)         ⇒ "3"
  (match 2)         ⇒ "14"

  (match 'integer)  ⇒ "3"
  (match 'fraction) ⇒ "14"

  (match 'after 'integer)   ⇒ ".14..."
  (match 'before 'fraction) ⇒ "pi=3."

Function: regexp-replace regexp string substitution
Function: regexp-replace-all regexp string substitution

string中でregexpにマッチした部分をsubstitutionで 置き換えます。regexp-replaceは最初にマッチした部分のみを置き換え、 regexp-replace-allは全てのマッチを置き換えます。

substitutionは文字列か手続きです。 文字列の場合、バックスラッシュに続く数値、もしくは \k<name>という形式でサブマッチ文字列を参照できます \0はマッチ文字列全体を参照します。文字列リテラルにバックスラッシュを 埋め込む場合は二つのバックスラッシュが必要であることに注意して下さい。 バックスラッシュそのものをsubstitution中で使いたい場合は 二つのバックスラッシュを重ねます; 文字列リテラルの場合は4つのバックスラッシュが 必要になります。

 
(regexp-replace #/def|DEF/ "abcdefghi" "...")
  ⇒ "abc...ghi"
(regexp-replace #/def|DEF/ "abcdefghi" "|\\0|")
  ⇒ "abc|def|ghi"
(regexp-replace #/def|DEF/ "abcdefghi" "|\\\\0|")
  ⇒ "abc|\\0|ghi"
(regexp-replace #/c(.*)g/ "abcdefghi" "|\\1|")
  ⇒ "ab|def|hi"
(regexp-replace #/c(?<match>.*)g/ "abcdefghi" "|\\k<match>|")
  ⇒ "ab|def|hi"

substitutionが手続きである場合、string中の各マッチについて、 マッチオブジェクトを引数としてその手続きが呼ばれます。その手続きが返す 値をdisplayで表現したものが置換文字列として使われます。

 
(regexp-replace #/c(.*)g/ "abcdefghi" 
                (lambda (m)
                  (list->string
                   (reverse
                    (string->list (rxmatch-substring m 1))))))
 ⇒ "abfedhi"

註: regexp-replace-all は文字列でマッチした部分の後ろの部分に ついて再帰的に自分自身を適用します。従って、regexpが 文字列先頭のアサーション (^) を含んでいても、それはstringの 先頭だけにマッチするとは限りません。

Function: regexp-replace* string rx1 sub1 rx2 sub2 …
Function: regexp-replace-all* string rx1 sub1 rx2 sub2 …

まず、regexp-replace あるいは regexp-replace-all を 正規表現 rx1、置換 sub1string に適用し、 その結果にさらに regexp-replace あるいは regexp-replace-all を正規表現 rx2、置換 sub2 で 適用し、以下同様です。これらの関数はひとつの文字列上で複数回置換を行う ときに便利です。

Function: regexp-quote string

string中で、正規表現において特別な意味を持つ文字を全てエスケープした 文字列を返します。

 
(regexp-quote "[2002/10/12] touched foo.h and *.c")
 ⇒ "\\[2002/10/12\\] touched foo\\.h and \\*\\.c"

以下のマクロにおいて、match-exprはマッチオブジェクトか #fを生成する式でなければなりません。通常それは rxmatchを呼ぶ式になりますが、それだけに限られるわけではありません。

Macro: rxmatch-let match-expr (var …) form …

match-exprを評価し、それがマッチオブジェクトを返したら、 マッチした文字列をvar …に束縛し、formを評価します。 最初のvarはマッチした文字列全体に束縛され、 以降の変数はサブマッチ文字列に束縛されます。実際のサブマッチ文字列が 与えられた変数より少なかった場合は、余った変数は#fに束縛されます。

特定のマッチ文字列を受け取る必要が無いときは、その場所の 変数の変わりに#fを置いておくこともできます。

 
(rxmatch-let (rxmatch #/(\d+):(\d+):(\d+)/
                      "Jan  1 23:59:58, 2001")
   (time hh mm ss)
  (list time hh mm ss))
 ⇒ ("23:59:58" "23" "59" "58")

(rxmatch-let (rxmatch #/(\d+):(\d+):(\d+)/
                      "Jan  1 23:59:58, 2001")
   (#f hh mm)
  (list hh mm))
 ⇒ ("23" "59")

このマクロはscshのlet-matchに相当します。

Macro: rxmatch-if match-expr (var …) then-form else-form

match-exprを評価し、それがマッチオブジェクトを返したら マッチした文字列を変数var …に束縛してthen-formを 評価します。マッチオブジェクトが返されなければ束縛は行われず、 else-formが評価されます。変数varをマッチ文字列に 束縛するルールはrxmatch-letと同じです。

 
(rxmatch-if (rxmatch #/(\d+:\d+)/ "Jan 1 11:22:33")
    (time)
  (format #f "time is ~a" time)
  "unknown time")
 ⇒ "time is 11:22"

(rxmatch-if (rxmatch #/(\d+:\d+)/ "Jan 1 11-22-33")
    (time)
  (format #f "time is ~a" time)
  "unknown time")
 ⇒ "unknown time"

このマクロはscshのif-matchに相当します。

Macro: rxmatch-cond clause …

clauseの条件を順に評価してゆき、条件を満たすものが現れたら そのclauseの残りのフォームを評価し、最後のフォームの値を rxmatch-condの値とします。clauseは以下のいずれかの 形式でなければなりません。

(match-expr (var …) form …)

match-exprを評価し、それがマッチオブジェクトを返した場合は マッチ文字列を変数var …に束縛した上で form …を評価します。

(test expr form …)

exprを評価し、それが真の値を返した場合はform …を評価します。

(test expr => proc)

exprを評価し、それが真の値を返した場合は それを唯一の引数として手続きprocを呼びます。

(else form …)

このclauseは、もし与えられたとすれば最後のclauseでなければ なりません。全てのclauseが失敗した場合に、form …が 評価されます。

else clauseが与えられず、かつ全てのclauseが 失敗した場合の戻り値は未定義です。

 
;; 何通りかの日付のフォーマットをパーズする
(define (parse-date str)
  (rxmatch-cond
    ((rxmatch #/^(\d\d?)\/(\d\d?)\/(\d\d\d\d)$/ str)
        (#f mm dd yyyy)
      (map string->number (list yyyy mm dd)))
    ((rxmatch #/^(\d\d\d\d)\/(\d\d?)\/(\d\d?)$/ str)
        (#f yyyy mm dd)
      (map string->number (list yyyy mm dd)))
    ((rxmatch #/^\d+\/\d+\/\d+$/ str)
        (#f)
     (errorf "ambiguous: ~s" str))
    (else (errorf "bogus: ~s" str))))

(parse-date "2001/2/3") ⇒ (2001 2 3)
(parse-date "12/25/1999") ⇒ (1999 12 25)

このマクロはscshのmatch-condに相当します。

Macro: rxmatch-case string-expr clause …

string-exprがまず評価され、続いてclauseが順に検査されます。 clauseは以下のいずれかの形式でなければなりません。

(re (var …) form …)

reはリテラル正規表現オブジェクトでなければなりません (正規表現参照)。string-exprの結果が文字列であり reにマッチした場合は、マッチ文字列が変数var …に 束縛され、formが評価されます。最後のformの値がrxmatch-case の値となります。

string-exprの結果の文字列がreにマッチしないか、 string-exprの結果が文字列以外であった場合は次のclauseへと 処理が進みます。

(test proc form …)

手続きprocstring-exprの結果を引数として呼ばれます。 それが真の値を返した場合はformが順に評価され、最後のformの 値がrxmatch-caseの値として返されます。

proc#fを返した場合は次のclauseへと 処理が進みます。

(test proc => proc2)

手続きprocstring-exprの結果を引数として呼ばれます。 それが真の値を返した場合は、その値を引数としてproc2が呼ばれ、 その返り値がrxmatch-caseの値として返されます。

proc#fを返した場合は次のclauseへと 処理が進みます。

(else form …)

このフォームは、与えられる場合は最後のclauseでなければなりません。 他の全てのclauseが失敗した場合に、formが順に評価され、最後のformの 値がrxmatch-caseの値として返されます。

else clauseが与えられず、かつ全てのclauseが 失敗した場合の戻り値は未定義です。

上のparse-dateの例はrxmatch-caseを使うとより単純になります。

 
(define (parse-date2 str)
  (rxmatch-case str
    (test (lambda (s) (not (string? s))) #f)
    (#/^(\d\d?)\/(\d\d?)\/(\d\d\d\d)$/ (#f mm dd yyyy)
     (map string->number (list yyyy mm dd)))
    (#/^(\d\d\d\d)\/(\d\d?)\/(\d\d?)$/ (#f yyyy mm dd)
     (map string->number (list yyyy mm dd)))
    (#/^\d+\/\d+\/\d+$/                (#f)
     (errorf "ambiguous: ~s" str))
    (else (errorf "bogus: ~s" str))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.