Next: , Previous: , Up: Forth Words   [Contents][Index]


6.25 Regular Expressions

正規表現(regular expression)は、 多くの現代的プログラミング言語で見られる、 文字列のパターン・マッチング・アルゴリズムです。 あなたは require regexp.fs を使用して正規表現機能を Gforth に追加できます。

このパターン・マッチングの古典的な実装はバックトラッキング・アルゴリズムです。 これは、 後方参照などの機能を使用する場合にも必要です。 Gforth は、 パターン・マッチングのためのバックトラッキング・プログラムを定義する言語(language)を提供することで正規表現を実装します。 基本要素は制御構造 FORKJOIN です。 これはワード内での前方呼び出しであるため、 軽量の試行錯誤制御構造(try and fail control structure)をコーディングできます。

FORK ( compilation – orig ; run-time f –  ) gforth-0.7 “FORK”

AHEAD のような制御構造: JOIN の後にコードを呼び出します。

JOIN ( orig –  ) gforth-0.7 “JOIN”

FORK のための、 THEN のような制御構造

あなたは、 チェックが失敗した場合に、 フラグと ?LEAVE を計算することで、 任意の種類のチェックを自分でプログラムできます。 正規表現コードは (()) で囲まれています。

(( ( addr u –  ) regexp-pattern “((”

正規表現ブロックの開始

)) ( – flag  ) regexp-pattern “))”

正規表現ブロックの終了

正規表現のパターン・マッチングには要素として文字セットがあるため、 多くの機能を使用して文字クラス(charclass と呼ばれる)を作成・変更できます。 ここでの文字はすべてバイトであるため、 ユニコード文字用には拡張されません。

charclass ( ) regexp-cg “charclass”

文字クラスを作成します

+char ( char –  ) regexp-cg “+char”

現在の文字クラスに char を追加します

-char ( char –  ) regexp-cg “-char”

現在の文字クラスから char を削除します

..char ( start end –  ) regexp-cg “..char”

char の範囲(startend)を現在の文字クラスに追加します

+chars ( addr u –  ) regexp-cg “+chars”

charの文字列(string)を現在の文字クラスに追加します

+class ( class –  ) regexp-cg “+class”

文字クラス class と現在の文字クラスの結合(union)

-class ( class –  ) regexp-cg “-class”

現在の文字クラスから、 文字クラス class を抜き取ります(subtract)。

事前定義された文字クラス(charclasses)とそれらのテストと、 一般的なチェックがあります。 チェックが失敗した場合は、 次に考えられる正規表現の代替が試行されるか、 または、 ループが終了(leave)します(訳注: 基本的には、 チェックが成功した場合は addr を 1文字(char)分進めた addr’ を返し、 失敗した場合はスタックに何も積まずに leave する)。

c? ( addr class – addr’ ) regexp-pattern “c?”

文字クラス class にマッチ(addr の位置の char が文字クラス class に含まれているなら addr の 1 char 次のアドレスを addr‘ に返し、 含まれていないなら leave する)

-c? ( addr class – addr’ ) regexp-pattern “-c?”

文字クラス class 以外にマッチ(addr の位置の文字が文字クラス class に含まれていなければ addr の1文字後ろのアドレスを addr’ に返し、含まれていたら leave する)

\d ( addr – addr’  ) regexp-pattern “\d”

数字([0-9])にマッチ(指定の addr の char が digit かどうか([0-9])しらべ、 そうなら addr の char 分次のアドレスを addr’ に返す。 そうでなければ leave する)

\s ( addr – addr’  ) regexp-pattern “\s”

非表示文字(\x00〜\x20)にマッチ(指定の addr の char が blanks かどうか([\x00-\x20])しらべ、 そうなら addr の char 分次のアドレスを addr’ に返す。 そうでなければ leave する)

.? ( addr – addr’  ) regexp-pattern “.?”

任意の1文字(char)にマッチ(任意の1文字(char)であれば次の文字のアドレスを addr’ に返します。 そうでなければ leave します)

-\d ( addr – addr’  ) regexp-pattern “-\d”

addr の文字が数字で無ければ([^0-9])次の文字のアドレスを addr’ に返します。 そうでなければ leave します。

-\s ( addr – addr’  ) regexp-pattern “-\s”

指定の addr の char が blanks で無いかどうか([^\x00-\x20])しらべ、 そうなら addr の char 分次のアドレスを addr’ に返す。 そうでなければ leave する

` ( addr "char" – addr’ ) regexp-pattern “‘”

指定の文字をチェックします。 ` c の形で使用し、 addr の文字が 文字 c ならば、 次の文字へのアドレスを addr’ に返し、そうでなければ leave します。

`? ( addr "char" – addr | addr’ ) regexp-pattern “‘?” 
\ 訳注: `? c  addr の文字が c ならば addr をそのまま返す。 c でなければ次の文字へのアドレスを addr’ に返す。
-` ( addr "char" – addr’ ) regexp-pattern “-‘” 
\ 訳注: -` c addr の文字が c でなければ次の文字へのアドレスを addr’ に返す。 そうでなければ leave する。

指定の文字をチェックします。 ` c の形で使用し、 addr の文字が 文字 c ならば、 次の文字へのアドレスを addr’ に返し、そうでなければ leave します。

明示的に文字列の開始と終了、および文字列定数全体をチェックすることもできます。

\^ ( addr – addr  ) regexp-pattern “\^”

文字列の開始にマッチ

\$ ( addr – addr  ) regexp-pattern “\$”

文字列の終了にマッチ

str=? ( addr1 addr u – addr2  ) regexp-pattern “str=?”

指定の文字列 addr u にマッチ(等しい)するかどうかチェックします(マッチすれば文字列の次のアドレスを addr2 に返します。 マッチしない場合は leave します)

doc-=” (原文未記述)

繰り返される文字セットをチェックするループは、 貪欲(greedy)または非貪欲(non-greedy)にすることができます。

{** ( addr – addr addr  ) regexp-pattern “begin-greedy-star”

貪欲な 0 個以上のパターンの開始

**} ( sys –  ) regexp-pattern “end-greedy-star”

貪欲な 0 個以上のパターンの終わり

{++ ( addr – addr addr  ) regexp-pattern “begin-greedy-plus”

貪欲な 1 つ以上のパターンの開始

++} ( sys –  ) regexp-pattern “end-greedy-plus”

貪欲な 1 つ以上のパターンの終わり

{* ( addr – addr addr  ) regexp-pattern “begin-non-greedy-star”

非貪欲な 0 個以上のパターンの開始

*} ( addr addr’ – addr’  ) regexp-pattern “end-non-greedy-star”

非貪欲な 0 個以上のパターンの終わり

{+ ( addr – addr addr  ) regexp-pattern “begin-non-greedy-plus”

非貪欲な 1 つ以上のパターンの開始

+} ( addr addr’ – addr’  ) regexp-pattern “end-non-greedy-plus”

非貪欲な 1 つ以上のパターンの終わり

例: 部分文字列の検索は、 実際にはその前にあるものとの非貪欲な一致です。

// ( ) regexp-pattern “//”

文字列内を検索(後続のパターンを文字列先頭ではなく文字列中でのマッチにする)(訳注:
: ([0-9]) ( addr u – ) (( \( \d \) )) IF ." [" \1 type ." ]" ELSE ." fail" THEN ;
"0123" ([0-9]) [0] ok
"A123" ([0-9]) fail ok
: (//[0-9]) ( addr u – ) (( // \( \d \) )) IF ." [" \1 type ." ]" ELSE ." fail" THEN ;.
"0123" (//[0-9]) [0] ok
"A123" (//[0-9]) [1] ok
"ABC3" (//[0-9]) [3] ok)

選択肢(alternative)は以下のように書きます。

{{ ( addr – addr addr  ) regexp-pattern “begin-alternatives”

選択肢(alternatives)の開始

|| ( addr addr – addr addr  ) regexp-pattern “next-alternative”

選択肢の区切り文字

}} ( addr addr – addr  ) regexp-pattern “end-alternatives”

選択肢の終了

\1\9 という名前の変数を最大 9 つ使用して、 一致した部分文字列を参照できます

\( ( addr – addr  ) regexp-pattern “\(”

マッチング変数の開始;変数は \\1〜9 として参照されます

\) ( addr – addr  ) regexp-pattern “\)”

マッチング変数の終わり

\0 ( – addr u  ) regexp-pattern “\0”

文字列全体

もちろん、 あなたは、 見つけたパターンを置換するコードを作成することもできます。

s>> ( addr – addr  ) regexp-replace “s>>”

検索/置換 の置換パターン領域の開始

>> ( addr – addr  ) regexp-replace “>>”

任意の置換コードを開始し、 コードはスタック上の文字列を評価し、 それを << に渡します。

<< ( run-addr addr u – run-addr  ) regexp-replace “<<”

置換パターン領域の先頭からを、 指定の文字列 addr u に置換します

<<" ( "string<">" –  ) regexp-replace “<<"”

置換パターン領域の先頭から文字列を string に置換します(訳注: 使い方: <<" string )

s// ( addr u – ptr  ) regexp-replace “s//”

検索/置換 ループの開始

//s ( ptr –  ) regexp-replace “//s”

検索の終わり

//o ( ptr addr u – addr’ u’  ) regexp-replace “//o”

検索/置換 の単一ループの終了

//g ( ptr addr u – addr’ u’  ) regexp-replace “//g”

検索/置換 の全てのループの終了

これらの使用例は test/regexp-test.fs にあります。


Next: Programming Tools, Previous: Object-oriented Forth, Up: Forth Words   [Contents][Index]