正規表現(regular expression)は、 多くの現代的プログラミング言語で見られる、 文字列のパターン・マッチング・アルゴリズムです。
あなたは require regexp.fs を使用して正規表現機能を Gforth に追加できます。
このパターン・マッチングの古典的な実装はバックトラッキング・アルゴリズムです。 これは、 後方参照などの機能を使用する場合にも必要です。 Gforth
は、 パターン・マッチングのためのバックトラッキング・プログラムを定義する言語(language)を提供することで正規表現を実装します。
基本要素は制御構造 FORK … JOIN です。 これはワード内での前方呼び出しであるため、
軽量の試行錯誤制御構造(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 の範囲(start 〜 end)を現在の文字クラスに追加します
+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 “‘?” \ 訳注:`? caddr の文字が c ならば addr をそのまま返す。 c でなければ次の文字へのアドレスを addr’ に返す。
-`( addr "char" – addr’ ) regexp-pattern “-‘” \ 訳注:-` caddr の文字が 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 にあります。