モダンな正規検索

検索パターン

 検索パターンは、いわゆる「正規表現」風に記述する。 「正規表現」は、万能の表現ではなく、時代により大きく変遷してきた。このため、CXTRA.EXE、LXTRA.EXEなどで使用していたパターンは、よく使われるPerlなどに搭載されたものと大きくずれてしまった。 そこで、主にPerlでの記法に近づけた形に記法を改めた。これが、ここで説明する「モダンな」正規検索である。 記述の文法、機能自体も処理系(というより、処理プログラム)によって大きく異なる。 従って、ここで指定するのは、このプログラム群独自の記述方法である。
 非常に多くの機能があって煩雑だが、多くは、内部機能を外に取り出したり、また、実験的な意図で設けたものである。すべてを覚える必要はない。
 拡張した要素の多くは「\=」「\/」で始まる。また、独自仕様のアンカー修飾は「\!」で始まる。  この三つの文字シーケンスで始まるものについては、当面、使用しなくても良い。

表記文字

以下に示すメタ文字・エスケープ文字・制御文字以外は、そのままで文字そのものを表わす。

メタ文字

特殊な機能や意味を持った文字。 指定した位置以外では通常の文字として扱われるものもある。

^検索パターンの先頭にある場合は行の先頭を表す。 クラス指定の先頭にある場合は否定集合を示す。
$ 行末を表す。
. 任意の1文字との一致を表す。
* 直前の単純要素の0個以上の一致を表す。
+ 直前の単純要素の1個以上の一致を表す。
? 直前の単純要素の0または、1個の一致を表す。
[ クラス指定の始まり。
] クラス指定の終わり。
- クラス指定の中のコードのつなぎ。
( 部分文字列指定の始まり。
) 部分文字列指定の終わり。
| 並列並びの区切り
{ 繰り返し指定の始まり。
} 繰り返し指定の終わり。
\< 文字列ブロックの始まり。
\> 文字列ブロックの終わり。
\1-\9 部分文字列を表す。
\= 部分文字列記述や、拡張したアンカー類などの記述の開始。
\! クラスの中では直前の要素の否定。クラスの後ろでは特殊なアンカーモード指定。
\/ 現在位置をマークする。
\d 組み込みクラス。数字1文字と一致。[0-9]と同じ
\D 組み込みクラス。数字以外1文字と一致。[^0-9]と同じ
\s 組み込みクラス。空白相当文字と一致
\S 組み込みクラス。空白相当文字以外と一致
\w 組み込みクラス。英数字と_に一致。[_0-9A-Za-z]と同じ
\W 組み込みクラス。英数字と_に不一致。[^_0-9A-Za-z]と同じ
\N 組み込みクラス。改行コード(\n)に不一致。[^\n]と同じ
\C 組み込みクラス。
\b 単語境界(アンカー)
\B 単語境界ではない場所(アンカー)
\m 単語先頭
\M 単語末尾
\A 論理行頭。
\Z 論理行末1。
\z 論理行末2。
\T いつも成立する(アンカー)
\F いつも成立しない(アンカー)

エスケープ文字

エスケープ文字は、メタ文字にあたる文字自身や制御文字を表すために使用する。 エスケープ記号の後の文字は大文字と小文字を区別する。

\a 制御文字 BELL(07h)
\b (制御文字 BS(08h)。クラス記述の中だけで有効)
\e 制御文字 ESC(1Bh)
\f 制御文字 FF(0Ch)
\n 制御文字 LF(0Ah)
\r 制御文字 CR(0Dh)
\t 制御文字 TAB(09h)
\v 制御文字 HM(0Bh)
\\\」自身
\..」自身
\**」自身
\++」自身
\??」自身
\||」自身
\((」自身
\))」自身
\{{」自身
\}}」自身
\[[」自身
\]]」自身
\--」自身
\^^」自身
\$$」自身
\: 何にも該当しない。常に読み飛ばされる。
\ \」の後ろにスペースを書く。スペース
\_ 「 」。スペース
\# 「#」。番号記号。シャープ。
\q 「'」。単引用符。
\Q 「"」。複引用符。
\cChr 英字で表す制御コード(0x00-0x1f)。\cA ならば 0x01
\xnn 16進数で表した1バイトコード
\jnnnn 16進数で表した漢字コード(JISコード)。
\Xnnnn 16進数で表した内部コード

制御文字(00h - 1Fh)

拡張書式

 アプリケーションでオプション指定(多くの場合は -S)することにより、拡張書式に切り替えることが出来る。

 拡張書式はパターンを見やすくするために導入されたもので、空白文字、制御文字をすべて無視するので自由な形式で要素を書ける。 また、# を書くと行末までを無視するので、# 以降行末まで注釈を書ける。
 パターン中に空白(0x20)を書く場合には、「\ 」を書けばよい(\の後ろにスペース)。 「\ 」はわかりにくいので、「\_」を書いてもよい。
また、# を書く場合には、「\#」を書けばよい。

検索パターンの構造

書式

要素の並び [| 要素の並び]
要素のならびが一つのパターンを表すが、それを 「|」で区切って並べることができる。 これらのパターンのどれかが成立することを表す。

要素

要素は、単純要素と複合要素(「(...)」)がある。

単純要素は、それ自身で単純な検索条件をあらわす。
複合要素は(「(...)」)の中に要素の並びを「|」で区切って書き、いずれかの要素並びが成立すれば、全体を成立とする(選択)。 また、複合要素には何種類かのバリエーションがある。

多くの要素は実際の文字に該当するパターンを表す。検索対象に該当する文字があれば、テキストポインタを進める。
これに対し、テキストポインターでの条件を検定するが、テキストポインタが決して進まない要素があり、これをアンカーと呼んでいる。

要素の後ろに修飾を書ける。修飾は、繰返修飾とアンカー修飾があり、要素によって使用できる修飾の種類が違う。どちらか一方の修飾を用いる。
繰り返し修飾は、要素の繰り返し回数を指定する。
アンカー修飾は、要素を検定の素材とするアンカーを指定する。

非アンカー要素

記法 名称









単純要素 中に別の要素を含まない単純な要素。繰返し修飾が出来る要素では、検索方法が指定でき、その順序で候補が見つかる。 複合要素よりもシステムのオーバーヘッドが少なく、一般に高速である。
c 文字 文字そのもの。
メタ文字以外の文字はそのまま、文字自身を表わす。
メタ文字に相当する文字を表すには \ を前につけてエスケープ表現する必要がある。 例えば、メタ文字でない $ を表すためには、\$ と書かなければならない。
. 任意の1文字

ピリオドは任意の1文字と一致する。 例えば、

a.b
は、「axb」や「azb」や「a缶b」などに一致し、「ab」とは一致しない。

ピリオドは、すべての文字に一致する。NULL(\x00)や改行コードも例外ではない。もっとも、改行コード自体の扱いは、ツールの取り扱いに依存する。

アンカー指定は殆どの場合意味がないので機能から省いた。 必要ならば、クラス文字 \C{any} に対してアンカー指定すればよい。
繰返修飾のうち、限定繰返は意味は殆ど意味がない。すべての文字が該当するのだから、連続の長さは文字列の長さとなる。 従って、入力文字列(あるいは行)の長さの検定としてのみ使える。

[...] クラス指定

[...]の中に書かれた文字範囲に一致する1文字を表す。

中に書ける要素は次の三種類。

文字 文字をそのまま書く。 [abc] ならば、a または b または c
文字範囲 文字を - でつないで書く。 この二つの文字を含む間の順序の文字が該当する。 [a-z] ならば a から z までの小文字アルファベットが該当する。
組み込みクラス文字 組み込みクラス文字を書ける。[a-z\d] ならば、a から z の小文字、または、半角数字(\d)を表す。

文字の検定は先頭から順に行い、その要素に該当した時点で成立とする。該当するものが一つもなければ不成立となる。

 [ ... ] の先頭に「^」を書くと、クラスの評価の全体を反転する。例えば、

[^0-9]
は、数字以外のすべての文字に該当する。

文字と文字範囲は後ろに \! を書くと、該当文字で不成立を示し、評価はそこで中断する。
例えば

[m\!a-z]
は、 m 以外の英小文字に該当する。最初に m\! で文字 m が除外され、a-z で残りの英小文字が選択される。

文字と文字範囲は後ろに \= を書くと、フィルター機能として働く。指定の範囲以外は不成立となる。指定の範囲では何もしない。
例えば

[A-Z\=\w]
は、 A-Z に該当する。最初に A-Z\= で A-Z 以外除外され、\w で英数字_が許されるが、結果的にA-Zになる。

組み込みクラス文字のうち、\C{any}\C{non} は特別な振る舞いをする。
\C{any} を評価すると必ず成立として中断し、 \C{non} を評価すると必ず不成立として中断する。

\s \S \d \D \w \W \N 組み込みクラス

よく使うクラス指定はメタ文字で指定できる。クラス指定の中でも記述できる。

\s[ \f\n\r\t\v] 空白文字一文字
\S[^ \f\n\r\t\v]空白文字以外一文字
\d[0-9] 数字一文字
\D[^0-9] 数字以外一文字
\w[_0-9A-Za-z] 英数字一文字
\W[^_0-9A-Za-z] 英数字以外一文字
\N[^\n] 改行コード以外
\C{name}
組み込みクラス

その他拡張したクラス文字。nameで種類を表す。クラス指定の中でも記述できる。
例えば、制御コード一文字は次のように表せる。

\C{control}

control制御文字
half半角文字
full全角文字
upper半角英大文字
lower半角英小文字
alpha半角英字
full_num全角数字
full_lower全角英小文字
full_upper全角英大文字
full_alpha全角英字
greek全角ギリシャ文字
russ全角ロシア文字
hiragana全角ひらがな
katakana全角カタカナ
kanji全角漢字
half_kana半角カタカナ
anyすべての文字が該当。クラス指定の中で使用すると強制成立。
nonすべての文字が不該当。クラス文字の中で使用すると強制不成立。
top文字列先頭の一文字
bottom文字列末尾の一文字
pre_eq直前の文字に等しい文字。直前に文字がない場合は、成立しない。
pre_ne直前の文字に等しくない文字。直前に文字がない場合も成立。
post_eq直後の文字に等しい文字。直後に文字がない場合は成立しない。
post_ne直後の文字に等しくない文字。直後に文字がない場合も成立。
\1-\9
\=nn;
部分文字列引用 ○*

検索対象の中で、メタ文字「(」と「)」の間で一致した部分は部分文字列として、 記述した順に番号を1から振って記憶される。

これらのうち最初の9つは、「\1」、「\2」、、「\9」で引用できる。
10番目以降では、\=の後に数字で番号を書き、 最後に;をつけて引用する。(もちろん、1-9番の部分文字列にも使用できるが…)

\=nn;

部分文字列の引用は、該当する部分文字列の指定の後でなければならない(引用時に不成立となる)。 また、部分文字列の指定自体は入れ子にして指定できる。

(.)\1
は、同一の2文字の連続パターンを表す。 このように、部分文字列として記憶されるのは、検索対象の文字列自身である。

\<...\> 文字列ブロック

ひとまとめの文字列。中にメタ文字やクラス指定をはさむことはできない。
要素として定義しているので処理速度は速いが、単独で使用する機会は少ないであろう。

エスケープされていない(「\」をつけない)メタ文字( * など)は、大抵、そのまま、文字を表すことが出来る。それ以外のメタ文字をここに含むことは出来ない。
例えば、"sin(40)" は、そのまま "sin(40) " と書く。"sin\(40\)" と書かなくても良い。
例外的に先頭に「?」を書く場合には、後先読み指定の「?」と区別するために、「\?」と書かなければならない。

繰返修飾を使った場合、最長一致は、最短一致共に正しく動作する。繰返限定指定も有効である。 同じ固定の文字列を使用するのであれば、( ... ) で記述するより、はるかに高速である。検索パターンのうち、修飾のない文字列は、内部的にこの文字列として扱われている。

アンカー修飾は有用である。アンカー修飾をすると繰返を指定は出来ないが、様々な先後読み検定として便利に扱える。

\<abcdefg\>{2}
abcdefg 二回の繰返し。
\=z 論理行末コード テキスト末尾か、改行コードに一致。
改行コードそのものにも一致する。
通常は使わない。暫定的仕様なので、将来削除する可能性がある。
複合要素 (...) で囲み、中に要素並びが入っているもの。または、その引用
( ... )
(?: ... )
(?; ... )
(?{nn} ... )
部分文字列指定 ○*

書式: ([?:|?;|?{nn}]要素並び[|要素並び]*)

パターン(要素並び)のいずれかが成立することを表す(選択動作)。書いた順に試していく。
要素の並びの中に入れ子にして (...) を書ける。一致した内容を部分文字列に格納できる。

開き括弧に続けて書く記号でいくぶん、機能が異なる。

( ... ) 括弧の直後に何も書かないと、単純な部分文字列指定。一致範囲が特定の番号の部分文字列に格納される。 (....)の左括弧が現れるたびに、番号を+1した新しい部分文字列が割り付けられる。一番最初の部分文字列の番号は1。
(?; ... ) ;はセミコロン。直前までの最大番号の部分文字列に一致範囲を格納する。
(abc)|(?;def)
ならば、(abc)は1番の部分文字列に格納する。(?;def)も、最後に現れた番号が1番なので、結局、同じ1番に格納する。
(?{nn} ... ) 指定の番号の部分文字列に格納する。番号は、検索パターン中に存在する範囲で指定する。
(?: ... ) :はコロン。一致結果を部分文字列に格納しない。パターンをまとめる括弧としてだけ働く。

部分文字列は、「\1」や「\=12;」などと書いて引用できる。 また、アプリケーションで取り出して利用できる。

可能な繰返修飾は、「?」「+」「*」「{min,max}」のみである。

繰返修飾をした場合、検出した繰返しの全体を部分文字列に格納する。

abcabc
に対して
^(.)+$
を適用した場合、部分文字列1番に入るのは、「abcabc」である。

繰返修飾をした場合の検索結果の順序は保証しない。つまり、処理系の都合で現れる順にマッチする(実際は、回数の少ない方から順に検定するので、最短一致風に動作するのだが)。従って、

w+
(w)+
は、論理的には同じパターンになるが、見つかる順序が変わるので、結果が異なる可能性がある。

\=x
\=x{nn}
パターン引用

記述した正規表現自体、あるいは、その一部を引用して評価する。

()で括った内容には、(の出現順に1番から順に番号が振られる。また、正規表現全体の番号は0とする。 この番号を nn で指定する。{nn}を省略すると、nnは0番となり式全体を示す。。

番号付けする引用先は、単純な(...)だけでなく、括弧(())でくくるすべてのものである。先後読み検定((?=...)など)や、注釈式((?%...))も含む。
部分文字列の番号付けとは全く違うことに注意が必要だ。

引用するのは()の内容なので、仮に、肯定的先読み(?= ... ) を引用しても、肯定的先読みとしては働かず、中の式(選択肢)の評価のみを行う。

単純に、\=xを式の内部で使用すれば、再帰的な適用となる。無限ループに陥りやすいので記述には注意が必要である。

アンカー

テキストポインターを進めず、その位置で検定だけを行うものをアンカーと呼んでいる。 代表的なものに、先頭「^」、末尾「$」アンカーがある。

記法 名称



単純要素 中に別の要素を含まない単純な要素。繰返し修飾が出来る要素では、検索方法が指定でき、その順序で候補が見つかる。 複合要素よりもシステムのオーバーヘッドが少なく、一般に高速である。
^ テキスト先頭 テキストポインタがテキスト先頭にある。
多くのアプリケーションでは、入力文字列=一行なので、行頭ということになる。
行頭以外の位置で 文字^ を使用する場合は、 \^ と書く(クラス定義の中などでは直に書ける)。 これは一般的な慣習に反するが、パターン内で行頭を書けるようにする為、あえて選択した。
$ テキスト末尾 テキストポインタがテキスト末尾にある。
多くのアプリケーションでは、入力文字列=一行なので、行末ということになる。
行末以外の位置で 文字$ を使用する場合は、 \$ と書く(クラス定義の中などでは直に書ける)。 これは一般的な慣習に反するが、パターン内で行末を書けるようにする為、あえて選択した。
^\! テキスト先頭ではない テキストポインタがテキスト先頭にない。
$\! テキスト末尾ではない テキストポインタがテキスト末尾にない。
\A
\=^
論理行頭

テキスト先頭か、直前に改行コードがある。\=^は互換性保持のために残してある。

\Z
\=$
論理行末1

テキスト末尾か、直後に改行コードがある。\=$は互換性保持のために残してある。

\z 論理行末2

直後に改行コードがある。

\G 検索開始位置 テキストポインタが検索開始位置にある。
CEXTRA.EXEのように複数回検索を繰り返すアプリケーションでは、結果が一致するごとに、検索開始位置を移動して検索を行う。
このときの指定された開始位置を示す。 一般にはパターンの先頭に書き、このときは、以降のパターンが必ず検索開始位置から始まることを示す。
\b 単語境界 現在位置の左右のいずれかが単語(英数字、_)である境界位置。
\B 非単語境界 現在位置の左右の双方が単語(英数字、_)、あるいは、単語でない。
単号の境界でないことを示す。
\m 単語の先頭 現在位置の左に単語(英数字、_)がなく、右に単語がある。
単語先頭の境界。
\M 単語の末尾 現在位置の左に単語(英数字、_)があり、右に単語がない。
単語末尾の境界。
\T いつも成立する。
\F いつも成立しない。
\<?=...\> 肯定的先読み文字列

テキストポインタの右から始まる文字列があることを示す。
繰返し回数は有効だが、最長最短の指定などは無意味である。

エスケープされていない(「\」をつけない)メタ文字( * など)は、そのまま、文字を表すことが出来る。それ以外のメタ文字をここに含むことは出来ない。
例えば、"sin(40)" は、そのまま "sin(40) " と書く。"sin\(40\)" と書かなくても良い。

\<?!...\> 否定的先読み文字列

テキストポインタの右から始まる文字列がないことを示す。
繰返し回数は有効だが、最長最短の指定などは無意味である。

エスケープされていない(「\」をつけない)メタ文字( * など)は、そのまま、文字を表すことが出来る。それ以外のメタ文字をここに含むことは出来ない。
例えば、"sin(40)" は、そのまま "sin(40) " と書く。"sin\(40\)" と書かなくても良い。

\<?<=...\> 肯定的後読み文字列

テキストポインタの左で終わる文字列があることを示す。
繰返し回数は有効だが、最長最短の指定などは無意味である。

エスケープされていない(「\」をつけない)メタ文字( * など)は、そのまま、文字を表すことが出来る。それ以外のメタ文字をここに含むことは出来ない。
例えば、"sin(40)" は、そのまま "sin(40) " と書く。"sin\(40\)" と書かなくても良い。

\<?<!...\> 否定的後読み文字列

テキストポインタの左で終わる文字列がないことを示す。
繰返し回数は有効だが、最長最短の指定などは無意味である。

エスケープされていない(「\」をつけない)メタ文字( * など)は、そのまま、文字を表すことが出来る。それ以外のメタ文字をここに含むことは出来ない。
例えば、"sin(40)" は、そのまま "sin(40) " と書く。"sin\(40\)" と書かなくても良い。

\/
\/{}
\/{nn}
現在位置マーク

書式: \/[{}|{nn}]
一致文字列中の現在位置をマークする。
文字列ブロックや、クラス指定の中には書けない。 出現順に1から99までの番号が振られる。

\/は、新たに新しい番号が付けられる。新しいマークが指定できるのは、この場合だけである。

\/{}は、最も新しく振られた番号と同じ番号を指定する。

アプリケーションにより機能が違うが、特定文字列の取り出し等に用いる。 CEXTRA.EXEでは、再検索の開始位置を指定するためにも使用出来る。

\=/?
\=/{}?
\=/{nn}?
マーク存在

書式: \=/[{}|{nn}]?
指定のマークがマークされていれば成立。

\=/?\=/{}?は、現在の位置で最大のマーク番号、

\=/!
\=/{}!
\=/{nn}!
マーク非存在

書式: \=/[{}|{nn}]!
指定のマークがマークされてなければ成立。

\=/!\=/{}!は、現在の位置で最大のマーク番号、

\=/_{...}
\=/{}_{...}
\=/{nn}_{...}
マークからの距離検定

書式: \=/[{}|{nn}]_{[^][min][,][max]}
指定のマークからの距離が範囲に入っていれば成立。距離は文字数。半角全角制御コードに関わらず1文字と数える。

_の後ろの{ ... }で範囲指定をする。範囲指定の先頭に^をつけると範囲外の時に成立となる。

\=/_{...}\=/{}_{...}は、現在の位置で最大のマーク番号を持つマーク。

\=/@{...}
\=/{}@{...}
\=/{nn}@{...}
マークからの幅検定

書式:\=/[{}|{nn}]@{[^][min][,][max]}
指定のマークからの幅が範囲に入っていれば成立。距離は文字数。半角制御コードは、1文字と数え、全角は2文字として数える。

@の後ろの{ ... }で範囲指定をする。範囲指定の先頭に^をつけると範囲外の時に成立となる。

\=/@{...}\=/{}@{...}は、現在の位置で最大のマーク番号を持つマーク。

\=nn? 部分文字列存在 指定した部分文字列に値がある事を表す。
\=nn! 部分文字列非存在 指定した部分文字列に値がない事を表す。
\=nn{...} 部分文字列数字検定 書式: \=nn{[^][min][,][max]}
指定した部分文字列を数値として解釈して、値が min以上max以下であることを表す。 「^」を指定すると範囲外を表す。
\=nn_{...} 部分文字列長さ検定 書式: \=nn_{[^][min][,][max]}
指定した部分文字列の長さが min以上max以下であることを表す。 「^」を指定すると範囲外を表す。
\=nn@{...} 部分文字列幅検定 書式: \=nn@{[^][min][,][max]}
指定した部分文字列の幅が min以上max以下であることを表す。 「^」を指定すると範囲外を表す。
全角文字は2として数え、それ以外は幅1として数える。
\=v{...} レベル検定 書式: \=v{[^][min][,][max]}
括弧のレベルが範囲内にある。
( .. ) で囲まれた中(部分文字列や、先後読み指定)に入るたびレベルが一つずつ増え、出ると、減る。 括弧の中にない部分のレベルは 0 。
範囲指定の頭に ^を書くと範囲外を表す。
\=v* レベルマーク 現在のレベルをマークする。
常に成立。
\=v?{....} レベルマーク検定 書式: \=v?{[^][min][,][max]}
マークしたレベルの値が範囲にある。
範囲指定の頭に ^を書くと範囲外を表す。
\=_+ パスカウント増加 パスカウントを+1する。
システムにひとつだけあるパスカウント(初期値は0)を増加させる。 常に成立。
\=_- パスカウント減少 パスカウントを−1する。
システムにひとつだけあるパスカウント(初期値は0)を減少させる。 常に成立。
\=_=nn; パスカウント設定 パスカウントに値をセットする。
常に成立。
\=_{...} パスカウント検定 書式: \=_{[^][min][,][max]}
パスカウントが範囲にある。
範囲指定の頭に ^を書くと範囲外を表す。
\=_* パスカウントマーク パスカウントを保存する。
常に成立。
\=_? パスカウントマーク一致 パスカウントとパスカウントのマークが同じ値。
\=_! パスカウントマーク不一致 パスカウントとパスカウントのマークが異なる値。
\=X{tsexpr} TSEXPRでの検定

 {} の間に書いた TSEXPR式を実行評価する。式の戻り値は BOOLでなければならない。
ここに書いた式は、文字列としてそのまま、バックトラック処理に渡され、バックトラックの探索の都度、解釈実行される。 TSEXPRはテキストインタプリタなので、構文解釈などが検索の試行のたびに行われ、決して高速ではない。実行回数が少なくなる書き方をしなければならない。{}の間で}を書く場合には、\} と書く必要がある。

SYS 関数は次のように定義されている。

機能
変数
説明
sys(n) n は正の整数。標準ではn 番の部分文字列。 sys(-10)からsys(-13)を呼び出すことでここでの返却する値を切り替える
部分文字列モード sys(-10)
??ustrmode
指定番号の部分文字列
マーク位置モード sys(-11)
??markmode
指定番号のマークの位置
部分文字列
先頭位置モード
sys(-12)
??topmode
指定番号の部分文字列の先頭位置
部分文字列
末尾位置モード
sys(-13)
??botmode
指定番号の部分文字列の末尾位置
sys(0)
??str
入力文字列
sys(-1)
??left
先頭から現在位置までの文字列
sys(-2)
??right
現在位置から末尾までの文字列
sys(-3)
??pos
現在位置(数値)
sys(-4)
??start
検索開始位置(数値)
sys(-5)
??level
現在のレベル(数値)
sys(-6)
??levelmark
レベルマークの値(数値)
sys(-7)
??passcount
パスカウント
sys(-8)
??passmark
パスカウントマーク
sys(-10)
??ustrmode
部分文字列モードを選択
sys(-11)
??markmode
マーク位置モードを選択
sys(-12)
??topmode
部分文字列先頭位置モードを選択
sys(-13)
??botmode
部分文字列末尾位置モードを選択
複合要素 (...) で囲み、中に要素並びが入っているもの。
(?= .... ) 肯定的先読み指定 ○*

書式 (?= 要素の並び [| 要素ならび]*)

テキストポインタの右にパターンを満たすものがあることを保証する。
テキストポインタの位置でパターン検索を行い、マッチを発見したところで打ち切り、成立とする。 すべての場合を尽くしてマッチしなければ不成立。

繰返し修飾はできるが、最短一致指定は無意味である。

(?! .... ) 否定的先読み指定 ○*

書式: (?! 要素の並び [| 要素ならび]*)

テキストポインタの右にパターンを満たすものがないことを保証する。
テキストポインタでパターン検索を行い、マッチすれば不成立。すべての場合を尽くしてマッチしなければ成立。
(?<= .... ) 肯定的後読み ○*

書式: (?<=[{nn}] 要素の並び [| 要素ならび]*)

テキストポインタの左にパターンを満たすものがあることを保証する。
テキストポインタから左へと順に検定を行う。それぞれの検定は成立すれば、打ち切り、その時点で全体の成立とする。
検定が成立しなければ、さらに右へテキストポインタを移して検定する。 こうして、文字列の先頭まで移動して成立しなければ、初めて不成立となる。

実用的な制限を加えるため、{nn}で現在位置からテキストの先頭へ戻って検定する制限文字数を指定できる。 一致する可能性のある(繰返し指定も考慮した)最大の文字数以上を指定すること。劇的な効果がある。

(?<! .... ) 否定的後読み ○*

書式: (?<![{nn}] 要素の並び [| 要素ならび]*)

テキストポインタの左にパターンを満たすものがないことを保証する。
テキストポインタから左へと順に検定を行う。それぞれの検定は成立ならば、打ち切り、その時点で全体の不成立とする。
検定すべての場合を尽くして不成立ならば、さらに右へテキストポインタを移して検定する。 こうして、文字列の先頭まで移動して成立しなければ、初めて成立となる。

実用的な制限を加えるため、{nn}で現在位置からテキストの先頭へ戻って検定する制限文字数を指定できる。 一致する可能性のある(繰返し指定も考慮した)最大の文字数以上を指定すること。劇的な効果がある。

(?# .... )(?% .... ) 注釈的パターン

書式(?#[{nn}] 要素の並び [| 要素ならび]*)
(?%[{nn}] 要素の並び [| 要素ならび]*)

普通の括弧の中のように中にパターン並びを書くが、書いたものは全く評価されない。
式引用実行(\=x{nn})でのみ評価できる。
内部は、評価されないだけの要素並びなので、部分文字列の番号付けや、マークの番号付けなど有効であるし、当然、正規表現の記法に沿って書かなければならない。 自由に記述できる、いわゆる注釈とは異なる。

(?#...)(?%...)の二つの記法を用意した。前者が意味合い的には良いが、注釈(#)を許す記法では、 (?\#...)と書く必要が生じる。このため、(?%...)を用意した。

(?*= .... ) 肯定的部分文字列検定

書式(?*[{nn}]= 要素の並び [| 要素ならび]*)

部分文字列を対象に正規検索を行い、成立すれば真とする。
対象とする部分文字列の番号は{nn}で指定する。nnが0または、番号指定を省略すると直前までの最大の番号の部分文字列を対象とする。

検索は特殊な形で行っているので多少の注意が必要だ。

・部分文字列の先頭は、検索開始位置として扱う。部分文字列の末尾は文字列の末尾として扱う。つまり、入力文字列を部分文字列の末尾で切り、検索開始位置を部分文字列の先頭としている。
・部分文字列の先頭は、「\G」と一致する。
・部分文字列の末尾は、「$」と一致する。
(?*! .... ) 否定的部分文字列検定

書式(?*[{nn}]! 要素の並び [| 要素ならび]*)

部分文字列を対象に正規検索を行い、成立すれば偽とする。
対象とする部分文字列の番号は{nn}で指定する。nnが0または、番号指定を省略すると直前までの最大の番号の部分文字列を対象とする。

検索は特殊な形で行っているので多少の注意が必要だ。

・部分文字列の先頭は、検索開始位置として扱う。部分文字列の末尾は文字列の末尾として扱う。つまり、入力文字列を部分文字列の末尾で切り、検索開始位置を部分文字列の先頭としている。
・部分文字列の先頭は、「\G」と一致する。
・部分文字列の末尾は、「$」と一致する。

修飾

繰返修飾

多くの要素の後ろに以下の記号をつけることで、繰り返しを表すことができる。 繰返し回数を、 ?(0回か1回)、 +(1回以上)、 *(0回以上)、 {..}(回数指定)を要素の後ろにつけることで表す。

検索の結果条件に合うものは複数見つかるが、見つける際の順序などで次の四つのバリエーションがある。

最長優先 もっとも長いものから順に見つける。標準の検索方法。
最短優先 もっとも短いものから順に見つける。繰返し記号の後ろに ? をつける
最大 もっとも長いものだけを候補とする。繰返し記号の後ろに + をつける
限定 指定回数のテキストの繰返しとだけ一致する。 一致した部分の外側に連続した繰返しはなく、連続した繰返しの個数そのものを検定する。 回数指定についてのみ指定可能で回数指定を{?....} と書く。
単純要素と複合要素では繰返手順が異なる。
単純要素では繰返し修飾が可能ならば、上の四通りの検定方法が有効である。
これに対して、複合要素((..))では、上の検索順序の指定はできず、一致の順序も保障しない。複合要素内部での単純要素そのものは記述に従った検索方法を取る。

* 0回以上の最長優先繰り返し 直前の要素の0回以上の繰り返し。長い方から検定する。
例えば、
ab*c
は、「ac」、「abc」、「abbbbbc」などと一致する。
a.*c
は、「.」が任意の文字なので、 「ac」、「axc」、「aasabc」などと一致する。
文字列「abcabcd」に対して検定すると、長い方から一致を見るので、 「abcabc」が最初の候補。
*? 0回以上の最短優先繰り返し 直前の要素の0回以上の繰り返し。短い方から検定する。
a.*?c
を文字列「abcabcd」に対して検定すると、短い方から一致を見るので、 「abc」を最初に見つける
*+ 0回以上の最大繰り返し 直前の要素の0回以上の繰り返し。 長い方から検定するが、見つかった最長の候補のみが一致する。
+ 1回以上の最長優先繰り返し 直前の要素の1回以上の繰り返し。長い方から検定する。
ab+c
は、「abc」、「abbbbc」などと一致する。 「*」指定と異なり、「ac」とは一致しない。
+? 1回以上の最短優先繰り返し 直前の要素の1回以上の繰り返し。短い方から検定する。
++ 1回以上の最大繰り返し 直前の要素の1回以上の繰り返し。 長い方から検定するが、見つかった最長のものだけが一致する。
? 0、1回の一致(最長優先) 「直前の要素の0または、1回の繰り返し」となっている。
?? 0、1回の一致(最短優先) 「直前の要素の0または、1回の繰り返し」となっている。短い方から検定する。
?+ 0、1回の一致(最大) 「直前の要素の0または、1回の繰り返し」となっている。 長い方から検定するが、見つかった最長のものだけが一致する。
{n,m} 指定回数の最長優先繰り返し 書式: {[n][,][m]}
直前の要素の指定回数の繰り返し。長い方から検定する。
nは最小の回数(0以上)、mは最大の回数を指定する。 nはmよりも大きくないように指定する。 (念のため、内部処理では、 n、mの大きな方を最大回数、小さな方を最小回数として扱っているが、 これに頼るべきではない。)
nを省略するとm以下の回数、mを省略するとn以上の回数の指定となる。
xa{1,3}
は、「xa」「xaa」「xaaa」と一致する。 「xaaaa」は、「xaaa」の部分が一致する。

{n,m}? 指定回数の最短優先繰り返し 書式: {[n][,][m]}?
直前の要素の指定回数の繰り返し。短い方から検定する
xa{1,3}?
は、「xa」と一致する。 「xaa」「xaaa」、「xaaaa」は、「xa」の部分が一致する。
a{1,3}?x
は、「ax」、「aax」「aaax」と一致する。 「aaaax」は、「aaax」の部分が一致する。 これは奇妙に見えるが、テキストポインタが2番目の「a」に進んだ時点で、 検索式の一致があるからである(最小回数から検定して長いものに、たどり着いた)。

{?n,m} 指定回数の限定繰り返し 書式: {?[n][,][m]}
直前の要素の指定回数の繰り返し。
繰り返し回数が厳密に範囲内であることを保障する。
<\abc\>{?1,2}
とかくと、「abc」「abcabc」は一致するが、「abcabcabc」には決して一致しない。
{n,m}+ 指定回数の最大繰り返し 書式: {[n][,][m]}+
直前の要素の指定回数の繰り返し。 長い方から検定するが、見つかった最長のものだけが一致する。

アンカー修飾

特定の要素を用いてテキストポインターの進まないアンカーを作り出す。
要素とアンカーの中間的なものも、この修飾で作り出す。
アンカー修飾は一般的には使用しなくても良い。 \b の類を自由に作る際に使用すると良い。

\!$ 現在位置の要素不一致 テキストポインタの右に指定の要素がない。 現在位置がテキスト末であれば、常に成立する。
\!^ 直前位置の要素不一致 テキストポインタの左に要素がない。 ポインタがテキスト先頭であれば常に成立する。
\!+ 現在位置の要素一致 テキストポインタの右に指定の要素がある。
\!- 直前位置の要素一致 テキストポインタの左に要素がある。
\!* 境界 テキストポインタの左右どちらかに一方に要素がある
\d\!*
数字の境界。
\!= 非境界 テキストポインタの左右に要素があるか、あるいは、双方に要素がない
\d\!=
数字の境界ではない。
\!_ 直前位置の要素一致 テキストポインタが先頭であるか、その左に要素がある
\n\!_
論理的な行頭。テキストポインタが先頭か、直前に改行コードがある。
\!/ 現在位置の要素一致 テキストポインタが末尾であるか、その右に要素がある
\n\!/
論理的な行末。テキストポインタが末尾か、直後に改行コードがある。
\!00 ポインタの左右で要素検定 テキストポインタの左右に要素がない
\!01 ポインタの左右で要素検定 テキストポインタの左に要素がなく、右に要素がある
\w\!01
単語の先頭
\!10 ポインタの左右で要素検定 テキストポインタの左に要素があり、右に要素がない
\w\!10
単語の末尾
\!11 ポインタの左右で要素検定 テキストポインタの左右に要素がある
\!; 要素またはテキスト先頭に一致 これはアンカーではない。
要素が一致すれば要素分ポインタが進み、成立 テキスト先頭ならば、ポインターが進まず成立。
暫定仕様。有用性の検討をしている。将来削除される可能性がある。
\!: 要素またはテキスト末尾に一致 これはアンカーではない。
要素が一致すれば要素分ポインターが進み、成立。 また、テキスト末尾ならば、ポインターが進まずに成立。
暫定仕様。有用性の検討をしている。将来削除される可能性がある。

追補

 何点かわかりにくい機能の説明を補う。

範囲の書き方

回数など数値の範囲の指定は、次の用に指定する(繰返し回数の場合は^が使えない)。

{{[^][min][,][max]}
わかりにくいので例を挙げておく。繰返し回数の場合は^が使えない事に注意。
{4,10}4 - 10。
{^4,10}4 - 10 以外。n <4 または n>10。
{4,}4以上。n>=4。{4,∞}と同じ。
{^4,}4未満。n<4。{^4,∞}と同じ。
{,10}10以下。n<=10。{0,10}と同じ。
{^,10}10より大。n>10。{^0,10}と同じ。
{5}5。{5,5}と同じ。
{^5}5以外。n≠5。{^5,5}と同じ。
{}0。{0,0}と同じ。
{^}0より大。{^0,0}と同じ。
{,}すべて。{0,∞}と同じ。
{^,}該当無し。{^0,∞}と同じ。

論理行の扱い

文字列の中に改行コードを入れると、文字列の中で複数の論理的な行を表すことが出来る。この改行コードの扱い方が多少面倒だ。
正規表現の中には、モードに応じて書き方の意味を変えることがあるが、これは避けたい(大文字小文字の区分指定だけはモードだが)。
.」(ピリオド)は、改行コードに一致しないシステムが多いが、本システムでは、どんな文字にも一致する。改行コードを特別扱いしない。
行頭と行末、あるいは、文字列先頭と文字列末尾のアンカーの意味は、次の通り。

^文字列の先頭
$文字列の末尾
\A論理行頭。文字列の先頭か、\n の直後。
\Z論理行末。文字列の末尾か、\n の直前。
\z論理行末。\n の直前。

最後の行の改行コードの有無の取り扱いは悩ましい。
abc\ndefabc\ndef\nは、行の中身としては同じものを示す。しかし、行末の検出は注意しなければならない。
\A.*?\Zabc\ndefでは二行を検出するが、abc\ndef\nからは、三行を検出する。最後の\nの後ろから行末の間の幅0の領域が一致するからだ。多少の注意が必要になる。0幅マッチしないパターンならば問題は無い。
アプリケーション lextra.exe cextra.exe では、行単位に処理する場合、改行コードは行に含まない。また、ファイル全体を読み込むモードでは標準の動作では、ファイル末尾の不完全行(改行コードがない)には改行コードを付加している。

条件節(if あるいは cond)

現在の機能の組み合わせで、条件分岐や、多条件分岐ができる。
記法名称
(if \/|)(\=/? then |\=/! else) 条件分岐

書式: (条件パターン\/|)(\=/? thenパターン |\=/! elseパターン)

 条件パターンは、一般的にはアンカーを書き、後ろにマークをする。アンカーが成立すれば(マークが設定され)、マークが存在するのでthenパターンが評価され、成立しなければ、マークが存在しないのでelse パターンが評価される。

((?=a)\/|)(\=/?abc|\=/!def)
条件 (?=a) が成立すれば abc を評価、成立しなければ def を評価する。

条件のANDとOR

アンカーで分岐できることがわかったが、分岐条件が複雑な場合のまとめを簡略に行える。

AND条件

パターンは順に実行するのだから、ただ、並べるだけでAND条件(途中で一つでも成立しなければ不成立)となる。

((?=cond1)(?=cond2)(?=cond3) .... )

実際は括弧を省いても、動作する。

OR条件

() 内の選択機能、つまり、パターンの | つなぎを使えばよい。

((?=cond1)|(?=cond2)|(?=cond3) | ... )

括弧は省けない。

部分文字列の番号付け

大まかに書けば、開き括弧「(」が現れるたびに新しい番号の部分文字列に格納が始まり、対応する閉じ括弧「)」で格納が終わる。 言い換えれば、部分文字列の番号付けは、開き括弧が現れるたびに行われる。

(abc(def(hijk)lmn(op)))
と書いたとき、記述と部分文字列は次のように対応する。
  1. (abc(def(hijk)lmn(op)))
  2. (def(hijk)lmn(op))
  3. (hijk)
  4. (op)

括弧は繰返しや、パターンの選択に使用するので、いつも、部分文字列を指定するの不便でわずらわしい。 そこで、特に次の書き方をした場合は、部分文字列に格納しない。従って部分文字列の番号付けの対象にならない。

(?:..)
同じように括弧で囲むが部分文字列に格納されないものに「先後読み指定」がある。次の四通りの記法である。
(?=...)
(?!...)
(?<=...)
(?<!...)

(?: ...( ... ) ... | ... (...) ... )のように書くと、部分文字列の取り込みは二箇所で行われるが、それぞれ、別の部分文字列に格納される。 中は選択動作なので、前に書いてあるものか、後ろに書いてあるものかいずれか一方しか成立しない。
この内容を参照するときに、この例ならば、部分文字列の1番と2番に結果が入る。これが同じ文字列に入った方が、後の処理(または、後のパターン)で扱いやすくなることが多い。 このため、後から定義するときに、既に存在する部分文字列と同じ番号を割り振る記法を追加した。

(?: ...( ... ) ... | ... (?;...) ... )
(?; ... )に割り振られる部分文字列番号は、現在までに出てきたもっとも大きな番号である。大抵の場合はこれは、直前の単純な開き括弧に対応する。 この例では、最初の部分文字列が1番で、次のものも1番となる。
同じ番号の部分文字列の中に同じ番号の部分を含むことは出来ない。先行する(同じ番号の)部分文字列の括弧が閉じていないと、同じ番号の部分文字列記述はできない。

上の簡略記法のみを使うと同一番号の部分文字列は連続して使用するしかない。「離れた」ところで使用するために、

(?{nn} .... )
という記法を追加した。nn で直接部分文字列番号を指定できる。

こういった込み入った記法を交えても、単純な開き括弧を数えれば部分文字列の番号がわかることは変わらない。

部分文字列の引用と検定

 部分文字列をパターン内で引用する記法が二種類ある。

過去、部分文字列が9個の制限があったので、直接的な記法、\1 \2 \3 ... \9 が使えた。 10番以上の部分文字列引用を示すために、\=10;などと書くことにした。この記法は、1―9番の部分文字列にも有効である。

いずれもアンカーとして(のように)働く。

マークと番号付け

マーク(\/)を書くと、そのテキストポインタの位置を記憶する。この情報は、アプリケーションで使用できる。(もともとは、アプリケーションに再検索する際の位置を検索一致以外の場所で指定するために設けたものであった)。
マークは99個あり、部分文字列と同様に \/ を書くたびに新しい番号が割り振られる。
現在のアプリケーションでは二つのマークを指定してその間を出力したり、置換の際に埋め込んだり出来る。
パターンないでも、マークの情報を使用した検定をいくつか用意した。

これも、部分文字列と同様だが、\/{}を書くと、今まで最大のマーク番号と同じ番号が割り振られる。別の選択肢の中にあるそれぞれのマークに同じ番号を振ると場合などに使う。

さらに、部分文字列に習って、\/{nn}を書くと、マーク番号を指定できる。

マークの検定

マークの検定は4種類要したが、いずれも、マークの番号を省略すれば、今まで割り振られた最大のマークの番号を指定する。 番号を指定する場合には、今まで現れたマーク番号の範囲で指定しなければならない。

  1. マークの存在検定(\=/?\=/!

    番号を指定する場合は、\=/{nn}?と書く。 最後に「?」がある方が、存在すれば成立、「!」で終わる方が存在すれば不成立を表す。
    選択肢の経過を記録してから、後での判断に使用できる。部分文字列でも出来るが、こちらの方が、シンプルに使える。

  2. マークからの距離検定(\=/{p}_{nn,mm}\=/{p}@{nn,mm}

    長い指定だが、マークの番号と、そのマークから現在位置までの距離を検定するための最大値と最小値を書く。 マーク番号を省略すると今まで現れた最大のマーク番号(多くの場合は直前のマークの番号)となる。
    \=/{p}_{nn,mm} は、全角半角制御コードのいずれも、一文字として数えるが、 \=/{p}@{nn,mm} は、全角を2、半角と制御コードは 1 として数える。

レベルと検定

ここで言うレベルは、パターンの()の深さを表す。括弧の中に入るたびに+1され、括弧から出るたびに−1される。 パターンを書いた時点で書く位置のレベルは決まってしまうので、レベル値自体の検定(\=v{min,max})はあまり意味がない。
ある時点でレベルを記憶し(\v*)、後にそれを判定する(\v?{min.max})ことができる。

パスカウントと検定

パスカウントは唯一つある数値記憶である。 パターンの中でこれに、値を書き込んだり(\=_=nn;)、+1(\=_+)したり、−1(\=_-)できる。 パスカウントの値は、範囲検定できる(\=_={min,max})。
主にネスティングする括弧を解析する際に用いるために設けた。 テキストの(を通過するたびに+1し、テキストの)を通過するたびに−1すればつりあった括弧の位置では同じ値に戻る。 この方法でネストする括弧(に類する問題)を解決できる。
この問題に限れば、パスカウントの検定は相対的で良いので、必要な場所で値を記憶し(\=_*)、抜け出したところで、記憶した値とパスカウントが等しければ(\=_?)抜け出したと判断できる。この方法では、パスカウントが相対化できるのがメリットである。 パスカウントとその記憶の不一致(\=_!)も用意されている。

再帰パターン

パターンの中にパターン自体を指定して再帰的な記述ができる。例を上げよう。
[a-z]\=x|,
パターン自体を示すのが \=x 。[a-z] であれば、また、自分自身を見て…、「, 」があれば、そこで終わる。
自己指定を通らない選択肢がないと、無限ループに陥るので注意が必要である。

パターン引用

書いたパターンの一部を引用できる。引用できるのは、パターン全体と、()で囲んだ内容である。(?=...)などはすべて対象となる。
開き括弧が出た順から、(が出るたびに番号が上がっていく。最初の括弧が1番で、0番はパターン全体を表す。
パターン引用は、一般的には \=x{nn}でパターン番号を指定する。

再帰パターンは、この機能のパターン番号を省略して0番(パターン全体)を指定した形で実現している。特定の括弧の中でその括弧を指定するパターン引用を行うと部分的再帰記述となる。

注釈的パターン((?%.....))は、書かれた場所では評価されないが、パターン引用できる。例えば、式の前の方で、定義しておけば、後方では同じ番号で、同じ記述を何回も参照できる。