MikoScript 言語仕様

 正規表現

 正規表現とは、文字列のパターンを表現する1記法です。正規表現では、様々な文字列
パターンを簡便に表現できるので、これを使えば、複雑な条件での文字列の検索/置換や、
各種の高度な字句解析等が容易に行なえるようになります。

 本言語の正規表現は、基本的な表記や機能を除いて、Perl 等の正規表現との互換性は
ありません。それよりも、機能の向上と表記の見易さに重点を置いています。そのため、
日本語の曖昧検索は勿論、パターン全体として真に最小または最大となる一致部の検索や、
従来不可能とされていた入れ子パターンの検索も可能になっています。また、一致文字列
パターンの識別値による区別も可能です。

●概要
 まず、本言語の正規表現の概要を、以下にまとめて示します。詳細は、後の関係各節で
述べます。

一致候補の採用優先順位
 (1)一致位置が、最左、または、最右
 (2)一致長が、最大、または、最小
 (3)一致パターンの識別値が、最小

メタ文字
  #  \  @  .  *  +  ?  |  (  )  [  ]  {  }  ^  $
  但し、
   ・# は、 %  /  '  `  $  のどれかに代替可。
   ・\ は、 %  /  '  `  のどれかに代替可。
   ・文字集合 [...] と [^...] 内では、\(または代替文字)と - のみがメタ文字。

メタ文字の変更
  @%  @/  @'  @`  @$ メタ文字 # を、それぞれ  %  /  '  `  $  に代替する
  @#                 メタ文字 # の代替を # 自身に戻す
  #%  #/  #'  #`     メタ文字 \ を、それぞれ  %  /  '  `  に代替する
  #\                 メタ文字 \ の代替を \ 自身に戻す
  #E                 全メタ文字を有効にする(デフォールト)
  #e                 全メタ文字を一時的に無効にする
  #x                 全メタ文字を恒久的に無効にする(再有効化は不能)

優先一致モード ( *はデフォールト )
  #L  *最左一致優先
  #R   最右一致優先
  #M  *最大一致優先
  #m   最小一致優先

文字比較モード ( *はデフォールト )
  #I  *英字大小の区別あり
  #i   英字大小の区別なし
  #Z  *全角半角の区別あり
  #z   全角半角の区別なし
  #K  *ひらかなカタカナの区別あり
  #k   ひらかなカタカナの区別なし
  #D  *かなの濁点半濁点有無の区別あり
  #d   かなの濁点半濁点有無の区別なし
  #T  *かなの大小の区別あり
  #t   かなの大小の区別なし
  #A  *全区別(英字大小/全角半角/かな種別/濁点有無/かな大小)あり
  #a   全区別(英字大小/全角半角/かな種別/濁点有無/かな大小)なし

翻訳制御モード ( *はデフォールト )
  #S  *空白( SP,HT,VT,FF,CR,LF )を有効にする(通常文字として扱う)
  #s   空白( SP,HT,VT,FF,CR,LF )を無効にする(読み飛ばす)

一致制御モード ( *はデフォールト )
  #P  *一致パターン識別値が示す参照グループとの一致不要
  #p   一致パターン識別値が示す参照グループとの一致必須

通常文字
  その文字自身に一致

任意文字
  .     任意の1字(改行は除く)に一致

エスケープ文字 (各対象の1字に一致)
  \d      数字 [0-9]
  \a      英字 [A-Za-z]
  \w      英単語文字 [A-Za-z0-9_]
  \s      空白 [ \t\r\n\f\v]
  \n      改行(CR/LF, LF, CR のどれか)
  \r      CR 単体( CR/LF の CR とは一致しない )
  \t      HT(水平タブコード: \x09 )
  \v      VT(垂直タブコード: \x0B )
  \f      FF(フォームフィードコード: \x0C )
  \e      ESC(エスケープコード: \x1B ) 
  \xnn    16進2桁 nn の1バイトコード
  \Xnnnn  16進4桁 nnnn の2バイトコード
  \Jnnnn  10進4桁 nnnn の2バイト句点コード
  \H      ひらかな [\J0401-\J0494]
  \T      カタカナ [\J0501-\J0594]
  \K      漢字 [\J1601-\J1694\J4801-\J9494]
  \Z      全角文字 [\J0101-\J9494]
  \k      半角カタカナ [\xA0-\xDF] 
  \h      半角文字 [\x20-\x7E\xA0-\xDF]
  \0      NUL(ヌル: \x00 )
  \ の次の1字が上記以外、または、1〜9 < > 以外の場合、その1字を表わす。
  ( 例: \\ は \ 自身を表わす )

文字集合
  [...]   ...で規定された文字集合に含まれる任意の1字に一致
  [^...]  ...で規定された文字集合に含まれない任意の1字に一致

連接
  XY    正規表現 X に続いて 正規表現 Y にも一致

分岐
  X|Y    正規表現 X または 正規表現 Y に一致

反復
  X+       1 回以上の正規表現 X に一致
  X*       0 回以上の正規表現 X に一致
  X?       0 回または 1 回の正規表現 X に一致
  X{n}     n 回の正規表現 X に一致
  X{n,}    n 回以上の正規表現 X に一致
  X{n,m}   n 回以上 m 回以下の正規表現 X に一致
  X{,m}    m 回以下の正規表現 X に一致

グループ
  (...)    グループ化された正規表現 ... に一致
  @(...)   参照グループ化された正規表現 ... に一致(バックリファレンス可)
  @=(...)  最重要参照グループ(一致部の代表として扱う)

バックリファレンス (一致済文字列部参照)
  @n    第 n 番目の参照グループと一致した文字列部に一致( n = 1,2,3,... )
  \n    (同上)

アンカー
  ^      検索テキストの先頭または行頭(改行コードの直後)に一致
  $       検索テキストの末尾または行末(改行コードの直前)に一致
  #[      検索テキストの先頭に一致
  #]      検索テキストの末尾に一致
  \<      英単語の先頭に一致
  \>      英単語の末尾に一致

先読み位置規定
  #(...)  正規表現 ... に一致する位置に一致
  #^(...) 正規表現 ... に一致しない位置に一致

グループ照合
  @[n]   第 n 番目の参照グループの正規表現に一致
       ( n = 1,2,3,... ; n = 0 の時は全体の正規表現 )

一致パターン識別値
  #n     この規定を通過したパターンの識別値を n に設定

通過カウント演算
  #=n     通過カウントを n に設定
  #+n     通過カウントに n を加算
  #-n     通過カウントから n を減算
  #==n    通過カウントが n と等しければ通過
  #!=n    通過カウントが n と等しくなければ通過
  #>n     通過カウントが n よりも大きければ通過
  #<n     通過カウントが n よりも小さければ通過
  #>=n    通過カウントが n よりも大きいか等しければ通過
  #<=n    通過カウントが n よりも小さいか等しければ通過
  #;      現通過カウント値を一致パターン識別値に設定

特別パターン規定
  #:():   丸括弧の囲い範囲に一致(入れ子を含む)
  #:{}:   波括弧の囲い範囲に一致(入れ子を含む)
  #:[]:   角括弧の囲い範囲に一致(入れ子を含む)
  #:<>:   HTMLタグ等の部分に一致(入れ子なし)
  #:'':   C 言語系の1重引用符囲いの文字リテラルに一致
  #:"":   C 言語系の2重引用符囲いの文字列リテラルに一致
  #:/*:   C 言語系のブロックコメントに一致
  #://:   C 言語系の行コメントに一致
  #:cw:   C 言語系の識別子に一致

各規定項の文法的関係 ( 以下の各 <...> は上記の各規定に対応 )
  正規表現:
    連接部
    正規表現 | 連接部
  連接部:
    連接単位
    連接部 連接単位
  連接単位:
    単項
    反復項
    ≪空≫
  単項:
    反復可能項
    反復不能項
  反復項:
    反復可能項 反復子
  反復可能項
    <通常文字>
    <任意文字>
    <エスケープ文字>
    <文字集合>
    <グループ>
    <バックリファレンス>
    <グループ照合>
    <特別パターン規定>
  反復子: (次のどれか)
    +  *  ?  {n}  {n,}  {n,m}  {,m} 
  反復不能項:
    モード項
    位置規定項
    特殊制御項
  モード項:
    <優先一致モード>
    <文字比較モード>
    <翻訳制御モード>
    <一致制御モード>
  位置規定項:
    <アンカー>
    <先読み位置規定>
  特殊制御項:
    <一致パターン識別値>
    <通過カウント演算>

●メタ文字
 正規表現の表記では、一部の文字が「メタ文字」として使われます。各メタ文字には、
特別な意味や機能があり、これがこの記法の根幹を成します。メタ文字以外は、通常文字
として扱われます。本言語の正規表現では、以下の 16 文字が、メタ文字になります。
   #  \  @  .  *  +  ?  |  (  )  [  ]  {  }  ^  $

 これらのメタ文字の各詳細については、後の各節で述べます。本節では、全メタ文字に
共通する事項と、# と \ のメタ文字の代替等について述べます。

 メタ文字の直前に \ を付けると、そのメタ文字は、通常文字に扱われます。つまり、
   \#  \\  \@  \.  \*  \+  \?  \|  \(  \)  \[  \]  \{  \}  \^  \$
は、それぞれ、上記の 16 個の各文字を表わす通常文字として扱われます。

 メタ文字の # は、
   @%  @/  @'  @`  @$
の指定で、それぞれ、 %  /  '  `  $  で代替させることができます。つまり、この指定
以降、# は通常文字になり、その代替文字がその役目を担うことになります。この代替は、
   @#
の指定で解除する( # の役目を # 自身に戻す)こともできます。これらの指定は、1つ
の正規表現内に複数あっても構いません。 # の代替は、後節で示すように、直記文字列
内で使うと便利です。
 なお、# を $ で代替した場合には、$ の次の文字が、# の代替として有意でなければ、
$ 本来のメタ機能( テキスト末尾/行末に一致 )になります。通常、この両用途が干渉
することはありません。

 メタ文字の \ は、
   #%  #/  #'  #`
の指定で、それぞれ、 %  /  '  ` で代替させることができます。つまり、この指定以降、
\ は、通常文字になり、その代替文字がその役目を担うことになります。この代替は、
   #\
の指定で解除する( \ の役目を \ 自身に戻す)こともできます。これらの指定は、1つ
の正規表現内に複数あっても構いません。

 本言語のソースプログラム内で、正規表現は、文字列リテラルで表わします。これには、
3形態の表記があることは、既に述べましたが、このうちのどれを使っても構いません。
例えば、ABC という正規表現は、
   "ABC"    $"ABC"    ##ABC##
の3形態で表記できます。ところで、最初の通常文字列の表記形態では、\ に予め特別な
機能が備わっているので、このリテラルで、正規表現のメタ文字 \ を表わすには、\\ と
する必要があります。例えば、\d+ という正規表現は、
   "\\d+"
とする必要があります。さらに、\ 自身を表わす正規表現は、\\ になりますが、これを、
通常文字列リテラルで表わすには、
   "\\\\"
とする必要があります。これでは大変なので、純粋文字列リテラルの表記にします。この
表記では、先程の正規表現は、
   $"\d+"     $"\\"
となります。このように、\ の使用が煩雑になる場合には、純粋文字列リテラルの表記を
使うと便利ですが、とりあえず、無条件に、正規表現の表記には、通常文字列リテラルを
使わないと決めておいた方が良いでしょう。そうすれば、正規表現を追加/修正する時に、
\ の個数が違っているのに気づかずに悩むことも減るでしょう。本書でも、特別な事情が
なければ、正規表現の表記に通常文字列リテラルは使いません。

 しかし、それでも、正規表現内で、\ を通常文字として使う箇所が多い場合には、\ の
使用が煩雑になります。また、直記文字列リテラル内では、\ をほとんど単独で使えます
が、特別な箇所もあります。このような不便は、メタ文字 \ の代替で回避できます。
 例えば、Windows や MS-DOS では、ファイルパスは、各ファイル名が、\ で区切られて
いますが、このような文字列に一致する正規表現を表わす場合には、\ が煩雑になります。
ここでは簡単のために、ファイル名を \w+ だけで表わすことにすると、その正規表現は、
次のようになります。
   $"(\a:\\?)?\w+(\\\w+)*"
ちなみに、これを通常文字列リテラルで表記すると、次のようになります。
   "(\\a:\\\\?)?\\w+(\\\\\\w+)*"
一方、メタ文字 \ を ` で代替させるようにして、これを書き換えると、
   $"#`(`a:\?)?`w+(\`w+)*"
となります。また、他の文字で代替させる場合には、以下のようになります。
   $"#%(%a:\?)?%w+(\%w+)*"
   $"#/(/a:\?)?/w+(\/w+)*"
   $"#'('a:\?)?'w+(\'w+)*"

 正規表現内のメタ文字は、
   #e
の指定以降、どれも一時的に通常文字として扱われるようになります。これを解除して、
本来のメタ文字の機能に戻すには、
   #E
を指定します。一方、
   #x
を指定すると、それ以降、どのメタ文字も、恒久的に通常文字として扱われるようになり
ます。一旦この状態になると、どのメタ文字も、元のメタ文字の機能には戻せません。

 次に、これらの指定を使った例を示します。
   "#e${LIB}"    "#x${LIB}"
この文字列リテラルはどちらも、${LIB} という文字列に一致する正規表現を表わします。
ここでは、$ { } の3つのメタ文字が、まとめて通常文字化されています。これは、以下
のように、各メタ文字を個別に通常文字化するよりも、便利です。
   $"\$\{LIB\}"   "\\$\\{LIB\\}"
以下の文字列リテラルは、${LIB} を含む行に一致する正規表現を表わします。
   "^.*#e${LIB}#E.*$"
ここでは、メタ文字を、#e で1度無効化した後、#E で再度有効化しています。

●エスケープ文字
 本言語の正規表現では、メタ文字の \ とアルファベット1字で、「エスケープ文字」を
表わします。但し、その後に文字コードが続くものもあります。エスケープ文字は、本章
の初節で示した通り、ある範疇に属する文字や、ある特定の文字を表わします。
 正規表現内のエスケープ文字は、それが表わす1字に一致します。例えば、
   \a
は、任意のアルファベット1字に一致します。これを使った次の正規表現
   m\a*o
は、m で始まり、o で終るアルファベット列に一致します。また、次の正規表現
   ^[ \t]*\n
は、空か空白だけの1行に一致します。これを、
   ^\s*\n
とすると、\s は改行コードにも一致するので、空か空白だけの行が連続する部分に一致
することになります。

 なお、\a のように、メタ文字 \ +アルファベット1字型のエスケープ文字は、現状、
文字比較モードには影響されない仕様になっています。例えば、#z で全角半角の区別無し
のモードになっていても、\a は半角の英字にしか一致しません。(ちなみに、そのモード
の時、[A-Z] は、全角の英大文字にも一致します。)

 文字コードを伴うエスケープ文字では、以下の3種類があり、その文字コードで任意の
1字を表わすことができます。
 ・\x に続く16進数字2桁の半角1バイトコードで、半角1字を表わせます。
 ・\X に続く16進数字4桁の全角2バイトコードで、全角1字を表わせます。
  なお、これらの文字コードは、現状、Shift-JIS コードに限定されます。但し、
 ・\J に続く10進4桁の句点コードでも、全角1字を表わせます。
以下に、これらの例を示します。
  A   \x41
  ア   \xB1
  あ  \X82A0  または  \J0402
  亜  \x889F  または  \J1601

 エスケープ文字として認識されるのは、\ の次の1字が、以下のどれかの文字の場合に
限ります。
   a d e f h H J k K n r s t T v x X w Z 0
この他にも、\ の次の1字には、
   1 2 3 4 5 6 7 8 9 < >
も使えますが、これは、エスケープ文字ではありません。

 \ の次が上記以外の文字の場合、その文字自身が通常文字として扱われます。例えば、
   \\  \#  \*  \C  \/
は、それぞれ、
   \  #  *  C  /
の通常文字として扱われます。

●文字集合
 文字集合は、任意の文字の集合を規定できます。この表記は、次のようになります。
   [...]
ここで、... のところに、その集合に含まれる文字を記述します。この記述には2通りの
形態があります。1つは、各文字を列挙する形態で、これは、例えば、
   [ABC]
のように記述します。これは、A,B,C の3字を含む文字集合を表わします。もう1つは、
文字の範囲を指定する形態で、これは、例えば、
   [A-Z]
のように、その範囲の最初と最後の文字の間に - を入れた表記になります。ちなみに、
この例は、大文字の全アルファベットを含む文字集合を表わします。なお、文字の範囲の
指定では、文字の順番を考慮する必要がありますが、それは文字コードの順になります。
 これらの2形態は、[...] 内に、混在させることができます。また、何回あっても構い
ません。例えば、
   [A-Za-z0-9_!]
は、大小の全アルファベットと数字と _ と ! を含む文字集合を表わします。

 正規表現内の文字集合は、その集合に含まれる文字に一致します。例えば、
   [ぁ-ん]
は、任意の全角ひらかな1字に一致します。なお、これは、\H とほぼ同じです。また、
   0[xX][0-9A-Fa-f]+
は、本言語等での16進定数の表記に一致します。

 文字集合は、補集合としても規定できます。その場合の表記は、次のようになります。
   [^...]
ここで、前と違って、[ の直後に ^ があります。... のところは、前と同様です。

 正規表現内の補集合の文字集合は、その集合に含まれない文字に一致します。例えば、
   [^ABC] または [^A-C]
は、A,B,C 以外の任意の1字に一致します。また、
   "[^"]*"
は、二重引用符で囲われた文字列リテラルに一致します。但し、この場合、二重引用符の
囲いの中に \" で二重引用符自身が入っている場合には一致しません。これにも一致する
正規表現については後で述べます。

 文字集合の [...] と [^...] 内の ... のところでは、
   \  -  ]
だけがメタ文字になります。これ以外の文字は全て、通常文字として扱われます。但し、
\ は、その代替文字になる場合もあります。これは、前述のエスケープ文字の表記のため
だけに使用され、それ以外の機能はありません。- は、上述の文字範囲の指定に使います。
また、 ] は、現文字集合の表記の終りを表わします。
 これらの文字を、... のところで、通常文字として使うには、それぞれ、
   \\  \-  \]
とします。なお、- が、[ または、[^ の直後、または、] の直前にあった場合、例えば、
   [-XYZ]   [^XYZ-]
のような場合には、文字範囲を表わせていないので、通常文字として扱われます。また、
   [$--]
のように文字範囲を示す - の直後に - がある場合も、通常文字として扱われます。

 文字集合内に、エスケープ文字が記述できるということは、例えば、
   [\a\d]  と  [A-Za-z0-9]
は、同じになります。また、
   [\H\T]
は、任意の全角ひらかなと全角カタカナの1字に一致します。また、
   #`"([^"\`n]|\(.|`n))*["`n]
は、二重引用符の囲いの中に \" で二重引用符自身が入っている場合にも、二重引用符の
文字列リテラルに適切に一致します。また、これは、二重引用符が1行内で閉じていない
場合、二重引用符から改行までと一致します。但し、\ の直後が改行の場合、それは次の
行へ続くものとして解釈されます。なお、ここでは、\ を ` で代替しているので、\ は
通常文字になり、改行は、`n という表記になっています。

 文字集合内に1字も規定されていない場合、つまり、
   []
は、空の文字集合になります。本言語では、これを任意の位置に一致する正規表現として
解釈しますが、実質的には、無項として読み飛ばします。これは、例えば、
   $"@(\A+)\s+@1[]2"
のように、バックリファレンス番号とそれに続く通常文字の数字との区切りや、
   ##@`#Macro[]abc##
のように、直記文字列内のマクロ名と通常文字の英字との区切りに使用できます。一方、
   [^]
は、空の文字集合の補集合です。本言語では、これをどの位置にも一致しない正規表現と
して解釈します。つまり、この位置以降には、どんな文字列パターンも一致しません。

●反復
 正規表現のある特定部分を反復するパターンは、以下の反復子で規定します。
   +       1 回以上
   *       0 回以上
   ?       0 回または 1 回
   {n,m}   n 回以上 m 回以下( 0 <= n <= m )
この反復子の反復対象は、その直前の単項になります。例えば、
   A+
では、A が1 回以上繰り返されている文字列( A  AA  AAA  等 )に一致します。

 反復対象と反復子の結合力は、連接の結合力よりも強いので、例えば、
   AB+
では、+ の対象は、B だけになります。そのため、この正規表現は、A で始まって、B が
1 個以上連続する文字列( AB  ABB  ABBB  等 )に一致します。AB が反復するパターン
を規定するには、以下のように、AB をグループ化する必要があります。
   (AB)+
この正規表現は、AB  ABAB  ABABAB  等に一致します。

 反復子の * と ? は、反復対象が 0 回の場合、つまり、反復対象がない文字列部にも
一致するので、注意が必要です。例えば、
   A*
は、任意の文字列の任意の位置の空文字列に一致します。勿論、これは、A  AA  AAA  等
にも一致します。例えば、
    "AAAX"'match( $"A*", M'new! );
    "XAAA"'match( $"A*", N'new! );
での一致部の抽出では、デフォールトの最左・最大の優先一致モードになるので、M は、
"AAA" になりますが、N は、空文字列になります。これは、正規表現 A* が、"XAAA" の
先頭位置で、長さ 0 の空文字列部に一致するからです。

 通常、A* のように、空文字列に一致する正規表現は、それ単独では用いずに、一致部
が必ず有限長の文字列になる正規表現と組み合わせて使います。例えば、
   A*B
は、A が 0 個以上連続した後に B がある文字列( B  AB  AAB  AAAB  等 )に一致する
ので、一致部が空文字列になることはありません。また、
   [-+]?\d+
は、- または + の符号の有無に関わらず、その次に1個以上の十進数字の列が続くので、
空文字列には一致しません。

 反復子の {n,m} には、以下のような省略型も存在します。
   {n}     n 回丁度( n >= 0 )
   {n,}    n 回以上( n >= 0 )
   {,m}    0 回以上 m 回以下( m >= 0 )
ここで、n と m は、実際には、十進数字列になります。以下に、これらの例を示します。
   so{1,2}n     son  soon  に一致
   (Go!){3}     Go!Go!Go!  に一致
   Ah{3,}!      Ahhh!  Ahhhh!  Ahhhhh!  等に一致
   Oh{,3}!      O!  Oh!  Ohh!  Ohhh!  に一致
なお、{n,m} で、n > m の場合( {3,2} 等 )は、どのようなパターンとも一致しません。
また、{n,m} 型の反復子でも、0 回の反復に一致する場合があるので、注意が必要です。

●分岐
 2つの正規表現のうちのどちらかに一致するパターンを規定するには、分岐を示す | 
を使います。例えば、
   A|B
は、A または B に一致します。
 分岐の | とその左右部との結合力は、連接の結合力よりも弱いので、例えば、
   abc|xyz
は、abc または xyz に一致します。この例は分かり易いのですが、例えば、
   count up|down
では、「count up」 または 「down」 に一致しますが、「count up」 または 「count down」 に
一致するわけではありません。このように一致させるには、
   count (up|down)
のように、グループ化する必要があります。

 3分岐以上のパターンを規定する場合も同様で、各分岐部を | で区切ります。例えば、
   A|B|C
は、A または B または C に一致します。また、
   You (can|may|must) be happy.
は、「You can be happy.」 と 「You may be happy.」 と 「You must be happy.」 に一致し
ます。

 分岐の | で区切られる各分岐部は、省略することもできます。その場合、その分岐部
は、空文字列に一致します。なお、空文字列に一致するというのは、前節で述べたように、
任意の文字列の任意の位置に一致するということです。例えば、
   A|
は、A または 空文字列 と一致します。これは、
   |A
でも同じです。また、これらは、A? と同じです。また、3分岐でも同様で、例えば、
   A|B|    A||B    |A|B
の3者はどれも、A または B または 空文字列 に一致します。これらは、(A|B)? と同じ
です。

●グループ化
 正規表現の特定部分を丸括弧で囲うと、その部分はグループ化されて、文法上の結合性
において、単項と同等の扱いになります。なお、単項の結合性に関しては、後節で述べて
います。
 例えば、反復子 + の対象は単項なので、A|B を反復の対象にするには、A|B+ とするの
ではなく、A|B をグループ化して、(A|B)+ とする必要があります。また、連接は、単項
または、単項に反復子が付いた項が、その単位になるので、A|B+ と C の連接は、A|B+C 
ではなく、A|B+ をグループ化して、(A|B+)C とする必要があります。

 グループ化されている中にグループ化されている部分があっても構いません。つまり、
グループ化は、何重にでも入れ子にできます。例えば、A(((B|C)+D)*E)F  も可能です。

 グループ化が特に必要ないところをグループ化しても、その効果は同じです。例えば、
ABCDEF は、(ABC)(DE)(F) でも ((AB(CD))(EF)) でも同じです。

 空文字列のグループ化、つまり、() は、可能ですが、これは、任意の文字列の任意の
位置の空文字列に一致するので、注意が必要です。

 左丸括弧に対応する右丸括弧が無い場合、文法的にはエラーになりますが、解釈上は、
その右丸括弧を補います。例えば、A(B|C は、A(B|C) と解釈します。また、A|(B+(C|D 
は、A|(B+(C|D)) と解釈します。

 右丸括弧に対応する左丸括弧が無い場合、文法的にはエラーになりますが、解釈上は、
その右丸括弧を無視します。例えば、A)B|C は、AB|C と解釈します。また、A(B|C)D) は、
A(B|C)D と解釈します。

●参照グループとバックリファレンス
 グループ化されている部分の先頭、つまり、左丸括弧の前に、@ を付けると、それは、
参照グループになります。例えば、AB@(CD)EF では、CD の部分が、参照グループです。
参照グループは、勿論、グループとしての機能を持ちますが、通常のグループとは違って、
参照グループに一致した文字列部は、後で参照することができます。例えば、AAABBBCCC 
というテキストと、A+@(B+)C+ という正規表現を照合した場合、参照グループの @(B+) 
は、BBB の文字列部と一致しているので、この BBB の部分が、後で参照できます。なお、
この「後で参照」というのは、その参照グループがあるのと同じ正規表現内か、または、
正規表現関連のシステム組み込み関数でできるということです。前者の場合、つまり、同
じ正規表現内で「後で参照」することを「バックリファレンス」と言います。

 バックリファレンスは、@ に続く十進数字列で表記します。例えば、@1 @2 などです。
この数字列の示す値は、そのバックリファレンスが、何番目の参照グループに対応するか
を示します。例えば、@3 は、第3番目の参照グループに対応します。
 正規表現内のバックリファレンスは、それが対応する参照グループが一致した文字列部
に一致します。例えば、
   @(A+)xyz@1
という正規表現内には、@(A+) の参照グループがありますが、これは、A, AA, AAA, ... 
に一致します。@1 のバックリファレンスは、この一致部に対応するので、正規表現全体
としては、それぞれ、AxyzA, AAxyzAA, AAAxyzAAA, ... に一致します。

 次に、別の例を示します。
   犬がワンワン吠えるので、はらはらした。
という文と、
   @(..)@1
という正規表現を照合すると、これは、「ワンワン」と「はらはら」の部分に一致します。
ここで、@(..) の参照グループは、任意の2字に一致するので、上文内にはその一致部が
多数ありますが、その次には @1 のバックリファレンスが続くので、その一致部の2字が
もう一度続く部分に限定されます。その部分は、上述の2箇所しかありません。ちなみに、
「キャンキャン」のように同じ3字が2回続くパターンにも一致する正規表現は、
   @(...?)@1
となります。

 次に、バックリファレンスが2箇所以上ある例を示します。
   @(.)@(.).@2@1
この正規表現は、「しんぶんし」のように、前から読んでも、後から読んでも同じになる
5文字の「回文」に一致します。7文字の回文には、以下の正規表現が一致します。
   @(.)@(.)@(.).@3@2@1
なお、5文字と7文字の両方の回文に一致する正規表現は、この両者を | で連結して、
   @(.)@(.).@2@1|@(.)@(.)@(.).@3@2@1
とすれば、良さそうですが、これでは、7文字の方のバックリファレンス @3@2@1 と対応
する参照グループの位置が合いません。これは、@5@4@3 にする必要があります。結局、
   @(.)@(.).@2@1|@(.)@(.)@(.).@5@4@3
が、5文字と7文字の回文に一致する正規表現になります。

 バックリファレンスの @ は、\ にすることもできます。しかし、参照グループの @ は、
\ にはできません。例えば、上記の5文字の回文に一致する正規表現は、
   @(.)@(.).\2\1
としても構いません。

 正規表現内のバックリファレンスの番号は、1 以上が有効です。従って、正規表現内の
@0 は、バックリファレンスとしては解釈されません。一般に、正規表現内で、@ の次が、
   1  2  3  4  5  6  7  8  9  (  =  [  #  %  /  '  `  $
以外の場合は、文法エラーになります。この場合、@ は通常文字に扱われます。
 @ の次が 1〜9 の数字で、それ以降 0〜9 の数字が続く間、つまり、非数字の直前まで、
その数字列は、バックリファレンスの番号として扱われます。そのため、この番号の上限
は特にありません。バックリファレンス番号の数字と、通常文字の数字を、区切るには、
[] を使います。例えば、バックリファレンス @12 の次に通常文字列の 34 がくる場合、
@12[]34 とします。
 バックリファレンスが対応する参照グループがないか、または、その一致部が確定して
いない場合、そのバックリファレンスは、どの文字列部とも一致しません。

●最重要参照グループ
 参照グループの表記 @(...) の @ の次に = を入れて、
   @=(...)
とすると、これは、最重要参照グループになります。
 最重要参照グループは、通常の参照グループとしての機能も勿論持ちますが、これが、
正規表現内に規定されていると、その正規表現の一致部を代表するのは、全体との一致部
ではなく、この最重要参照グループとの一致部になります。
 例えば、
   テキスト   ---AAABBB---
   正規表現   @=(A+)B+
を照合した場合、正規表現全体には、テキスト内の AAABBB の部分が一致しますが、この
正規表現の一致部を代表するのは、最重要参照グループ @=(A+) と一致する AAA の部分
になります。これを、実際の実行例で示すと、以下のようになります。
    print "--AAABBB--"'match( $"@=(A+)B+", M'new! ), M;   // → 0, AAA

 正規表現内に最重要参照グループがあっても、それとは無関係に、その正規表現に一致
する範囲が一旦確定されます。その上で、最重要参照グループに一致する部分が無ければ、
その一致は無効になり、その範囲が読み飛ばされれて、その範囲の直後から、検索が再開
されます。例えば、
   テキスト   ---ABC---XYZ---
   正規表現   ABC|@=(XYZ)
を照合した場合、まず、ABC の部分に一致しますが、これには最重要参照グループに一致
する部分が無いので、その部分が読み飛ばされて、その直後から、検索が再開されます。
そして今度は、XYZ に一致しますが、これには最重要参照グループに一致する部分が有る
ので、この一致部が採用されます。

 この特性を利用すると、例えば、HTML テキストで、タグの外側の通常のテキスト部分
だけを対象にして、特定の文字列を検索することができます。ちなみに、その検索対象が、
ABC という文字列の場合、その正規表現は、以下のようになります。
   #m<.*>|@=(ABC)
なお、この HTML タグに一致する正規表現は、簡易用で、厳密にはもっと複雑になります。
次に、2重引用符で囲われた文字列リテラルの外側にある ABC と一致する正規表現は、
   #:"":|@=(ABC)
となります。また、C 言語系のコメントの外側にある ABC と一致する正規表現は、
   #:/*:|#://:|@=(ABC)
となります。なお、ここで使っている #:"": と #://: と #:/*: の表記に関しては、本
章の「特別パターン規定」の節で説明しています。

 最重要参照グループは、1つの正規表現内に1つしか指定できません。もし、2つ以上
あれば、最後のものだけが有効になります。

●アンカー
 アンカーは、検索対象のテキスト内の位置との一致を規定するものです。これは、文字
と一致するものではありません。アンカーには、
   ^   $   #[   #]   \<   \>
があります。

 ^ は、行頭に一致します。ここで、行頭というのは、検索対象テキストの先頭、または、
そのテキスト内にある改行コードの直後の位置を意味します。
 $ は、行末に一致します。ここで、行末というのは、検索対象テキストの末尾、または、
そのテキスト内にある改行コードの直前の位置を意味します。

 例えば、以下の正規表現
   ^.*ABC.*$
は、ABC という文字列を含む任意の1行に一致します。この一致部の範囲は、改行コード
の直前までで、改行コードは含みません。また、検索対象テキストの最後に改行コードが
ない場合でも、そのテキストの末尾までになり得ます。従って、この正規表現を、以下の
どの文字列と照合した場合でも、--ABC-- の部分と一致します。
   "--ABC--"
   "--ABC--\n--XYZ--\n"
   "--XYZ--\n--ABC--\n--123---"
   "--XYZ--\n--ABC--"

 なお、改行コードまでを含めた行に一致させるには、$ の代わりに、\n を使います。
例えば、以下の正規表現
   ^\s*XYZ.*\n
は、先頭の空白部の有無に関わらず、XYZ という文字列で始まる任意の1行の、行頭から
改行コードまでに一致します。

 ところで、^ は、検索対象テキストの先頭か改行コードの直後にしか一致しないので、
例えば、ABC^ のように、通常文字の次が ^ になるパターンは存在しません。また、同様
に、$ は、改行コードの直前か検索対象テキストの末尾にしか一致しないので、例えば、
$ABC のように、$ の次が通常文字になるパターンは存在しません。本言語の正規表現は、
このような場合でも、^ と $ を通常文字として扱うことはありません。また、正規表現
内で、必ずしも、^ が最初で、$ が最後になる必要はありません。そのため、例えば、
空行か空白だけの行が連続するところに一致する正規表現は、以下のように書けます。
   (^[ \t]*\n)+

また、行末の XYZ か、行頭の ABC に一致する正規表現は、
   XYZ$|^ABC
と書けます。これは、
   ^ABC|XYZ$
と書くのと同じですが、これは、決して、
   ^(ABC|XYZ)$
と同じではないので、注意が必要です。

 #[ と #] は、それぞれ、検索対象テキストの先頭と末尾の位置に一致します。例えば、
検索対象テキストの先頭の空白部に一致する正規表現は、以下のようになります。
   #[\s+
また、検索対象テキストの末尾の空白部に一致する正規表現は、以下のようになります。
   \s+#]

 \< と \> は、それぞれ、英単語の先頭と末尾の位置に一致します。但し、ここで言う
英単語とは、通念上の「英単語」とは若干違い、以下のどれかの文字が1つ以上連続する
文字列部のことを意味します。
   英大小文字 [A-Za-z] 
   数字 [0-9]
   _ (アンダースコア)
なお、これらの文字を「英単語文字」と呼ぶことにします。これは、エスケープ文字の
 \w に該当します。また、この英単語文字以外の文字を「非英単語文字」と呼ぶことに
します。
 この英単語の先頭ということは、非英単語文字から英単語文字へ変わる境目ということ
です。あるいは、検索対象テキストの先頭が英単語文字ならその先頭もそうです。一方、
この英単語の末尾ということは、英単語文字から非英単語文字へ変わる境目、あるいは、
検索対象テキストの最後が英単語文字ならその末尾ということです。

 例えば、この英単語は、以下の文字列において、~~~ で示した部分になります。
   ABC  P12  -34.567  MAX_SIZE  NP-89  St.XYZ  山と海
   ~~~  ~~~   ~~ ~~~  ~~~~~~~~  ~~ ~~  ~~ ~~~        

 次に、\< と \> を使った正規表現の例を示します。
   \<c\a*n\>
この正規表現は、c で始まり n で終る任意の英単語に一致します。これは、can, clean,
common 等、あるいは、couldn't の couldn に一致しますが、control の con や ocean 
の cean 等には一致しません。

 アンカーは、通常、それ単独では用いずに、一致部が有限長の文字列になる正規表現と
組み合わせて使います。さもなければ、その一致部は、空文字列になるので、注意が必要
です。

●先読み位置規定
 先読み位置規定は、一種のアンカーで、検索対象テキスト内の特定位置との一致を規定
するものです。この規定の表記は、以下のように、正規表現を伴い、これに一致する位置、
または、一致しない位置が、その特定位置になります。
  #(...)    ... の正規表現に一致する位置に一致
  #^(...)   ... の正規表現に一致しない位置に一致

 例えば、検索対象テキストが、
   I think this is the fourth matter.
として、#(th) は、think, this, the の先頭の3箇所と、fourth の four と th の間に
一致します。一方、#^(th) は、それ以外の個所に一致します。また、#(is) は、this の
th と is の間と is の先頭に一致し、#^(is) は、それ以外の箇所に一致します。

 次に、もう少し複雑な例を挙げます。

#i\<#^((this|that)\>)th\a*\>
 これは、th で始まる英単語(但し、this と that は除く)に一致します。

#i\<#^(th)t\a*\>
 これは、t で始まる英単語(但し、th で始まるものは除く)に一致します。

#i\<\a+#(-?like\>)
 これは、like か -like で終る英単語(但し、一致部に like と -like は含めない)
 に一致します。

^#^(.*ABC).*
 これは、ABC を含まない行に一致します。(これは空行にも一致するので要注意)

 #(...) 内の正規表現に、参照グループ、バックリファレンス、一致パターン識別値、
通過カウント演算等を、入れることは可能です。しかし、
 #^(...) 内の正規表現では、一致しない時が有意なので、ここに、一致する時に有意に
なる参照グループや、一致パターン識別値を入れても、無意味です。

 先読み位置規定の一致部は、空文字列になるので、それ単独で使う場合や、一致部が空
文字列になることがある正規表現と組み合わせて使う場合には、注意が必要です。

 #^ の直後は必ず (...) でなければいけません。さもなければ、文法エラーになります。
その際、#^ は無視されます。一方、# の直後は、(...) 以外にもいろいろありますが、
所定外の場合には、# は通常文字に扱われます。

●グループ照合
 正規表現内に同じ部分が2回以上ある場合、グループ照合を使うと、2回目以降の同じ
部分を簡略して表記できます。例えば、
   [AIUEO]+\a*[AIUEO]+
という正規表現では、[AIUEO]+ が2回がありますが、グループ照合を使うと、
   @([AIUEO]+)\a*@[1]
のように記述できます。ここで、@[1] がグループ照合の表記です。これは、第1番目の
参照グループの正規表現( ここでは、[AIUEO]+ )と同じであることを意味します。

 グループ照合の書式は、一般に、
   @[n]
となります。ここで、n は実際には十進数字列になります。この数字列の示す値は、その
グループ照合が、何番目の参照グループに対応するかを示します。例えば、@[3] は、第
3番目の参照グループに対応します。この対応は、バックリファレンスの場合と同様です。
但し、グループ照合では、n が省略、または、0 の時、つまり、
   @[] または @[0]
で、その正規表現全体に対応させることができます。

 グループ照合は、その規定部が、その対応部分と同じ正規表現になることを意味します。
これは、最初の例のように、グループ照合がその対応部分に含まれていなければ、同部分
の単なる繰り返しにしか過ぎませんが、グループ照合がその対応部分に含まれている場合、
それは、「再帰的なグループ照合」になります。

 再帰的なグループ照合を使うと、例えば、入れ子を含んだ丸括弧のパターンに一致する
正規表現を、以下のように簡潔に表記できます。

   \(([^()]|@[])*\)

これについて以下に説明します。まず、入れ子を1つも含まない丸括弧のパターンは、
   \([^()]*\)
と表わせます。これを、※ とすると、入れ子を最大1個まで含む丸括弧のパターンは、
   \(([^()]|※)*\)
と表わせます。これを、※ とすると、入れ子を最大2個まで含む丸括弧のパターンは、
   \(([^()]|※)*\)
と表わせます。以降同様に、入れ子を最大 N 個まで含む丸括弧のパターンを ※ とする
と、入れ子を最大 N+1 個まで含む丸括弧のパターンは、
   \(([^()]|※)*\)
と表わせます。この「入れ子を N+1 個まで含むパターン」は、「入れ子を N 個まで含む
パターン」にも一致するので、※ を @[] に置き換えることができます。

 なお、再帰的なグループ照合での再帰の深さは、現状、8レベルまでに限定されます。
そのため、上記の正規表現は、入れ子を9個以上含む丸括弧のパターンには一致しません。
例えば、((((((((())))))))) は最外の括弧に一致しますが、(((((((((()))))))))) では、
この1つ内側の括弧にしか一致しません。

●モード
 本言語の正規表現では、メタ文字の # とアルファベット1字で、モードを表わします。
モードには、本章の初節で示した通り、以下の種類があります。
  ・優先一致モード
  ・文字比較モード
  ・翻訳制御モード
  ・一致制御モード
このうち、最初の3モードは、次の各節で説明しますが、最後のモードは、一致パターン
識別値に関連するので、その節の後で、説明します。

●優先一致モード
 優先一致モードは、正規表現が複数の文字列部に一致した場合、どの候補を優先するか
を決めるモードで、正規表現と一致した部分が、以下の各条件で選ばれます。
   最左優先 ・・・ 最も左側(先頭に最も近い)
   最右優先 ・・・ 最も右側(先頭から最も遠い、つまり、末尾に最も近い)
   最大優先 ・・・ 最も長い(文字コードのバイト数が最も多い)
   最小優先 ・・・ 最も短い(文字コードのバイト数が最も少ない)
優先一致モードの組み合わせは、以下の4通りです。
   #L#M  最左・最大
   #L#m  最左・最小
   #R#M  最右・最大
   #R#m  最右・最小
このうち、「最左・最大」がデフォールトになります。

 例えば、
   ABC---XYZ
という文字列に対して、正規表現
   \a+
は、以下の 12 箇所に一致します。
   A  AB  ABC  B  BC  C  X  XY  XYZ  Y  YZ  Z
このなかで、各優先一致モードで選ばれるのは、以下の箇所です。
   最左・最大  ABC
   最左・最小  A
   最右・最大  XYZ
   最右・最小  Z

 優先一致モードは、正規表現全体に対するモードなので、正規表現内のどこに置いても、
また複数あっても構いませんが、有効なのは最後に指定されたモードだけです。そのため、
通常、優先一致モードは、正規表現の最初か最後にだけ置きます。

 本言語の優先一致モードでは、たとえ分岐や反復がどのようになっている正規表現でも、
その正規表現全体に一致する全候補の中から、真にその条件に合致するものが選ばれます。
最初の分岐が優先されるとか、各反復部分で最大/最小になるとかは、関係ありません。
とにかく、正規表現全体としての条件で選ばれます。

 以下に、優先一致モードを使った実行例を示します。
    T = "  =AA=BB=CC=   =XX=YY=ZZ=  ";
    T'match( $"#L#M=[^\s]*=", M'new! );  print M;   // → =AA=BB=CC=
    T'match( $"#L#m=[^\s]*=", M'new! );  print M;   // → =AA=
    T'match( $"#R#M=[^\s]*=", M'new! );  print M;   // → =XX=YY=ZZ=
    T'match( $"#R#m=[^\s]*=", M'new! );  print M;   // → =ZZ=

●文字比較モード
 文字比較モードは、対象の文字列内の文字と、正規表現内の文字とを、どのように比較
するかを規定するモードで、以下の種類があります。
  #I #i  英字大小の区別の有無
  #Z #z  全角半角の区別の有無
  #K #k  ひらかなカタカナの区別の有無
  #D #d  かなの濁点半濁点付きの区別の有無
  #T #t  かなの大小の区別の有無
  #A #a  全文字種別の区別の有無
ここで、それぞれ、# の次が、大文字なら区別有りで、小文字なら区別無しになります。
なお、デフォールトは、どれも区別有りの方です。

 この文字比較モードでは、例えば、
   「A」  と 「a」  は、#I で不一致、#i で一致
   「ア」 と 「ア」  は、#Z で不一致、#z で一致
   「あ」 と 「ア」 は、#K で不一致、#k で一致
   「か」 と 「が」 は、#D で不一致、#d で一致
   「つ」 と 「っ」 は、#T で不一致、#t で一致
となります。また、
   「あ」 と 「ア」  は、#z#k で一致
   「は」 と 「パ」 は、#k#d で一致
   「は」 と 「パ」 は、#z#k#d で一致
   「Aだよ」 と 「Aタョ」  は、#i#z#k#d#t つまり #a で一致
となります。

 文字比較モードは、正規表現内のどこに置いても、また、複数あっても構いませんが、
その効力は、各分岐で個別に働きます。例えば、
  #iA|B
という正規表現は、#iA と B の2分岐がありますが、それぞれ、文字比較モードは個別
なので、A は大文字と小文字の両方に一致しますが、B は、デフォールトで英字の大小が
区別されるので大文字にしか一致しません。つまり、この正規表現は、A と a と B に
一致しますが、b には一致しません。

 また、グループ内で、文字比較モードを変更していても、そのグループの終了時点で、
そのグループの開始時点での文字比較モードの状態が復帰されます。例えば、
  (#iA)B
という正規表現では、(#iA) のグループ開始時点では、デフォールトの #I 状態なので、
グループ内で #i に変更しても、グループの終了時点では、#I に戻ります。そのため、
この正規表現は、AB と aB に一致しますが、Ab と ab には一致しません。一方、
  #i(A#IB)C
という正規表現では、(A#IB) のグループ開始時点では、#i 状態なので、グループ内で 
#I に変更しても、グループの終了時点で、#i に戻るため、A は #i、B は #I、C は #i 
が適用されます。また、
  A|#i(B(#IC|D))E|F
という正規表現では、A と C と F は #I、B と D と E は #i が適用されます。

●翻訳制御モード
 翻訳制御モードは、正規表現の翻訳の仕方を制御するモードで、以下の2つがあります。
  #S  正規表現内の空白を通常文字として扱う(デフォールト)
  #s  正規表現内の空白を読み飛ばす
ここで、空白というのは、次のどれかの文字コードのことです。
  SP ( \x20 ) 半角空白
  HT ( \x09 ) 水平タブ
  VT ( \x0B ) 垂直タブ
  FF ( \x0C ) フォームフィード
  CR ( \x0D ) キャリッジリターン
  LF ( \x0A ) ラインフィード

 正規表現内に #s の指定があると、それ以降、#S の指定があるまで、これらの空白が
読み飛ばされます。但し、読み飛ばされるのは、文法上、通常文字として解釈される所に
ある空白だけに限られます。文字集合の [...] 内等の空白は、対象外になります。また、
反復の {...} 内等にむやみに空白を入れることもできません。

 空白が読み飛ばされるモードにしておくと、空白を随所に挿入できるので、正規表現を
見易くできます。例えば、
   $"\w+\\\w+"
という正規表現の文字列リテラルは、以下のように、各要素間に空白を入れて書けます。
   $"#s \w+ \\ \w+"

また、以下は、コマンド行の各パラメータを解析するための正規表現の文字列を、変数
CmdLineRegex に代入する文です。ここでは、囲い文字を ' にした純粋文字列リテラルを、
連続表記していますが、これらは、「文字列リテラル」の章の
   ・文字列リテラルの連続表記
の節で述べたように、1つの文字列に解釈されます。
    CmdLineRegex = 
        $'#`'                       // メタ文字変更  \ → `
        $'`s+#1|'                   // 空白
        $'[-/]@(.)@([^`s]*)#2|'     // コマンドオプション  @1 @2
        $'[^-/`s\"][^`s]*#3|'       // ファイル名
        $'"@([^"]*)"#4';            // 二重引用符で囲まれた文字列  @3
これを、以下のように、空白を入れて、比較的見易くすることができます。
    CmdLineRegex = 
        $'#s#`'                        // メタ文字変更  \ → `
        $' `s+                #1 |'    // 空白
        $' [-/]@(.)@([^`s]*)  #2 |'    // コマンドオプション  @1 @2
        $' [^-/`s\"][^`s]*    #3 |'    // ファイル名
        $' "@([^"]*)"         #4  ';   // 二重引用符で囲まれた文字列  @3
●一致パターン識別値  一致パターン識別値は、正規表現のどのパターンに検索対象のテキストが一致したかを 識別するための値です。この表記は、以下のようになります。    #n ここで、n は、実際には十進数字列になり、その値が識別値になります。例えば、#1 や #2 は、それぞれ、1 と 2 の一致パターン識別値になります。この表記は、非十進数字の 直前まで続くと解釈されます。そのため、この表記の次に通常文字の十進数字が続く場合、 その間の区切りが必要になりますが、それには、[] 等を使います。[] は既に述べた通り、 実質的に読み飛ばされるだけです。例えば、一致パターン識別値 #12 の次に 34 の通常 文字が続く場合、#12[]34 とします。  一致パターン識別値は、正規表現の文法上、単項と解釈される所ならどこにでも入れる ことができますが、各識別対象のパターンを特定できる場所に置く必要があります。また、 この値の振り分けは任意で、各パターン毎でも、各種別ごとでも構いません。  例えば、以下の正規表現    AAA#1|BBB#2|CCC#3 は、検索対象テキスト内の AAA の部分と一致した場合には、そのパターンの識別値が 1 になり、BBB の部分と一致した場合には、2 になり、CCC の場合は、3 になります。この 正規表現を実際に使った実行例を、以下に示します。
    'match( $"AAA#1|BBB#2|CCC#3" );   // 正規表現の事前設定
    print "--AAA--"'match( , M'new! ), M;   // → 1, AAA
    print "--BBB--"'match( , M'new! ), M;   // → 2, BBB
    print "--CCC--"'match( , M'new! ), M;   // → 3, CCC
 また、例えば、以下の正規表現    AAA(#1|XXX#2) は、AAA か AAAXXX に一致しますが、そのどちらなのかを区別できます。また、    (#3|XXX#4)AAA は、AAA か XXXAAA に一致しますが、そのどちらなのかを区別できます。これらを使った 実行例を、以下に示します。
    print "--AAABBB--"'match( $"AAA(#1|XXX#2)", M'new! ), M;   // → 1, AAA
    print "--AAAXXX--"'match( $"AAA(#1|XXX#2)", M'new! ), M;   // → 2, AAAXXX
    print "--BBBAAA--"'match( $"(#3|XXX#4)AAA", M'new! ), M;   // → 3, AAA
    print "--XXXAAA--"'match( $"(#3|XXX#4)AAA", M'new! ), M;   // → 4, XXXAAA
 一致パターン識別値は、字句解析等で使うと便利です。例えば、以下は、コマンド行を、 コマンドオプション、ファイル名、二重引用符で囲まれた文字列、の各パラメータに分割 してプリントするプログラムです。
    CmdLineRegex =   // コマンド行解析用正規表現
        $'#s#`'                        // メタ文字変更  \ → `
        $' `s+                #1 |'    // 空白
        $' [-/]@(.)@([^`s]*)  #2 |'    // コマンドオプション  @1 @2
        $' [^-/`s\"][^`s]*    #3 |'    // ファイル名
        $' "@([^"]*)"         #4  ';   // 二重引用符で囲まれた文字列  @3

    // コマンド行の文字列をバッファに書き出す
    T = ::Buffer();
    T.Write( $'/p -x12 file1.c dir\f2.x "file #3"' ); 
    T.Seek(0);

    // バッファ内のコマンド行の各要素を正規表現との照合で抽出していく
    for( cn = T.Find( CmdLineRegex ) ; cn >= 0 ; cn = T.FindNext() )
    {
        cp = T.FoundText();
        switch( id = T.FoundID() )
        {
          case 1:  break;  // 空白
          case 2:  print id, cn, cp, T.FoundText(1), T.FoundText(2);  break;
          case 3:  print id, cn, cp;  break;
          case 4:  print id, cn, cp, T.FoundText(3);  break;
        }
    }
このプログラムを実行すると、以下の通りプリントされます。 2, 2, /p, p, 2, 4, -x12, x, 12 3, 7, file1.c 3, 8, dir\f2.x 4, 9, "file #3", file #3  一致パターン識別値が指定されていないパターンに一致した時のパターン識別値は、0 になります。例えば、以下の通りです。
    print "--AAA--"'match( $"AAA|BBB#2", M'new! ), M;   // → 0, AAA
    print "--BBB--"'match( $"AAA|BBB#2", M'new! ), M;   // → 2, BBB
 同じ文字列部に、同じ優先一致モードで、複数のパターンが一致する場合、その識別値 が最小となるパターンが選ばれます。例えば、以下の通りです。
    print "--CCC--"'match( $"C+#1|\a+#2|C#ic*#3", M'new! ), M;   // → 1, CCC
    print "--CCC--"'match( $"C+#3|\a+#2|C#ic*#1", M'new! ), M;   // → 1, CCC
●一致制御モード  一致制御モードには、現状、#P と #p があります。これらは、一致パターン識別値に 対応する参照グループの一致部分の有無によって、正規表現全体の一致の有効性を決める か否かを指定するモードです。  #P は、正規表現全体の一致を常に有効にする指定で、これがデフォールトになります。  #p は、一致パターン識別値に対応する参照グループが無いか、または、有ってもその 一致部分が無ければ、その正規表現全体の一致を無効にする指定です。  なお、一致パターン識別値と参照グループとの対応は、バックリファレンスと同様で、 その値が何番目かを示します。例えば、#3 は、第3番目の参照グループに対応します。  例えば、    @(ABC)(#1|XYZ#2) という正規表現では、    ABC または ABCXYZ の文字列部に一致し、その一致パターン識別値はそれぞれ、1 と 2 になります。ここで、 一致制御モードが #P の場合には、この両者の一致は有効です。しかし、#p の場合には、 ABC の一致は有効ですが、ABCXYZ の一致は無効になります。なぜなら、ABC の一致での 一致パターン識別値 1 に対応する1番目の参照グループの一致部分は有りますが、一方、 ABCXYZ の一致での一致パターン識別値 2 に対応する2番目の参照グループの一致部分は 無いからです。  #p のモードを使うと、正規表現に一致する範囲をいろいろと絞り込むことができます。 例えば、    #p(#1|XYZ#2)@(ABC) は、XYZ が先行しない ABC の部分に一致する正規表現になります。また、    #p(#1|X+#9)@(A+)|(#2|Y+#9)@(B+) は、X+ が先行しない A+ か、または、Y+ が先行しない B+ に一致する正規表現です。 また、次の正規表現は、// ... と /* ... */ のコメント外にある XYZ に一致しますが、 このコメント内にある XYZ には一致しません。    #p#s @(XYZ) #1 | #://: #2 | #:/*: #2 なお、ここでは、#s で、空白を入れて若干見易くしています。また、#://: と #:/*: の 表記に関しては、本章の「特別パターン規定」の節で説明しています。  正規表現が #p モードであっても、それとは無関係に、その正規表現に一致する範囲が、 一旦確定されます。その上で、その一致範囲の有効性が確認されて、もし無効なら、その 範囲が読み飛ばされれて、その範囲の直後から、検索が再開されます。  例えば、本節の最初の例で、#p モード指定の場合、    #p@(ABC)(#1|XYZ#2) となりますが、この正規表現を、    ---ABCXYZ---ABC---XYZ--- という文字列と照合する場合、一旦、ABCXYZ に一致しますが、これは、#p の条件に合致 しないので、その一致は無効になり、その部分が読み飛ばされて、その直後から、検索が 再開されます。そして、今度は、ABC に一致しますが、これは #p の条件に合致するので、 その一致は有効になります。  ところで、この場合の検索は、デフォールトの最大一致優先ですが、これを、    #p#m@(ABC)(#1|XYZ#2) として、最小一致優先の検索にすると、ABCXYZ の部分であっても、ABC が一致部になり、 #p の条件に合致します。そのため、この一致が、有効になってしまいます。  なお、この例では、最小一致優先にすると所望の結果が得られなくなりましたが、逆に、 最小一致優先にしないと所望の結果が得られない場合もあります。  また、上記の文字列に対して、    #p@(ABC)(#1|XYZ#2)|XYZ という正規表現と照合させた場合、最初に一致が確定するのは、ABCXYZ の部分ですが、 この部分は、#p の条件に合致しないため、読み飛ばされます。そして、検索はこの部分 の直後から再開されます。そのため、この部分中の XYZ には、正規表現内の分岐の XYZ と一致することはありません。  #p モードであっても、その正規表現に一致する部分の一致パターン識別値が 0 の場合、 その一致は無条件に有効になります。例えば、    #p@(ABC)(#1|XYZ#2)|PQR という正規表現と、    ---ABCXYZ---PQR--- という文字列を照合した場合、最初に、ABCXYZ の部分に一致しますが、これは読み飛ば されて、次に PQR の部分に一致します。この部分の一致パターン識別値はデフォールト の 0 なので、この一致は無条件に採用されます。  #P と #p は、正規表現全体に対するモードなので、1つの正規表現内では、どちらか 1つしか指定できません。2つ以上あっても効力があるのは最後の指定だけです。なお、 #P はデフォールトなので、明示的に指定する場合以外、実質的には、#p の有無で、この モードの状態が決まります。 ●通過カウント演算  通過カウント演算は、正規表現と検索対象テキストとの照合が進行する過程で、一致部 が、その指定箇所に達した時に行なわれます。この通過カウント演算の指定は、正規表現 の文法上、単項と解釈される所ならどこにでも、設定できます。通過カウント演算の対象 は、「通過カウント」で、これは、各パターン遷移毎に1つ存在し、その初期値は、0 に なります。本章の初節で示した通り、通過カウント演算には、以下があります。   #=n #+n #-n #==n #!=n  #>n #<n #>=n #<=n #; ここで、n は、実際には十進数字列になります。負値の場合、その前に - の符号を付け ます。正値の場合、+ の符号は付けません。n は、省略可能で、その場合、各演算ごとの デフォールト値になりますが、それは、#+ と #- では、1 で、それ以外の演算では、0 になります。この通過カウント演算の表記は、非十進数字の直前まで続くと解釈されます。 そのため、この表記の次に通常文字の十進数字が続く場合、その間の区切りが必要になり ますが、それには、[] 等を使います。[] は既に述べたように、実質的に読み飛ばされる だけです。例えば、通過カウント演算 #=12 の次に 34 の通常文字が続く場合、#=12[]34 とします。  #=n は、通過カウントの値を n を設定します。例えば、#= #=12 #=-3 は、それぞれ、 通過カウントの値を、0, 12, -3 に設定します。  #+n と #-n は、それぞれ、通過カウントの値を n だけ加算、減算します。例えば、#+ は、通過カウントの値に 1 を加算し、#+4 は 4 を加算します。 #- は、通過カウントの 値から、1 を減算し、#-5 は 5 を減算します。  #==n と #!=n は、それぞれ、通過カウントの値と n が、等しか、等しくないかを比較 して判定します。例えば、#== は、通過カウントの値が 0 と等しいかを判定し、#==6 は、 6 と等しいかを判定します。 #!= は、通過カウントの値が 0 と等しくないかを判定し、 #!=-7 は、-7 と等しくないかを判定します。  #>n と #<n は、それぞれ、通過カウントの値が n よりも大きいか、小さいかを、比較 判定します。例えば、#> は、通過カウントの値が 0 よりも大きいかを判定し、#>8 は、 8 よりも大きいかを判定します。 #< は、通過カウントの値が 0 よりも小さいかを判定 し、#<9 は、9 よりも小さいかを判定します。  #>=n と #<=n は、それぞれ、通過カウントの値が n よりも大きいか等しいか、小さい か等しいかを、比較判定します。例えば、#>= は、通過カウントの値が 0 よりも大きい か等しいかを判定し、#>=10 は、10 よりも大きいか等しいかを判定します。 #<= は、 通過カウントの値が 0 よりも小さいか等しいかを判定し、#<=12 は、12 よりも小さいか 等しいかを判定します。  これらの比較判定の結果が正しい場合、そのパターン遷移は継続されます。一方、その 結果が正しくない場合、そのパターン遷移は中止されます。つまり、もはやそのパターン では一致しないと判断されます。例えば、通過カウントの値が 3 の時、#>=2 の演算では、 そのパターンは継続され、#==4 の演算では、中止されます。  #; は、現通過カウントの値を、一致パターン識別値に設定します。この設定によって、 一致したパターンが、通過カウントで識別できるようになります。なお、この表記には、 n はありません。  通過カウント演算を使えば、一致したパターンの特定部分が何回反復されているかを、 知ることができます。例えば、AAAX* という正規表現は、AAA の後に X が 0 回以上続く 文字列部に一致しますが、X が何回続いた文字列に一致したかは分かりません。一方、    AAA(X#+)*#; という正規表現を使うと、その一致パターン識別値で、X が何回続いたかが分かります。 以下に、これを実際に実行する例を示します。
    'match( $"AAA(X#+)*#;" );  // 正規表現の事前設定
    print "--AAA--"'match( , M'new! ), M;      // → 0, AAA
    print "--AAAX--"'match( , M'new! ), M;     // → 1, AAAX
    print "--AAAXX--"'match( , M'new! ), M;    // → 2, AAAXX
    print "--AAAXXX--"'match( , M'new! ), M;   // → 3, AAAXXX
 通過カウント演算を使うと、従来不可能とされていた「入れ子を含むパターン」に一致 する正規表現を記述できます。例えば、「丸括弧の入れ子を含んだ囲い範囲」に一致する 正規表現は、以下のようになります。    \((\(#+|[^()]|\)#-#>=)*\)#== 以下に、これについて説明します。まず、丸括弧は、メタ文字なので、\( と \) と表記 しないといけませんが、これでは分かりにくいので、当面、その代わりに、≪ と ≫ を 使うことにします。また、空白を随所に入れて、もう少し見易くします。そうすれば、上 の正規表現は、以下のようになります。    #s ≪ ( ≪ #+ | [^≪≫] | ≫ #-#>= ) * ≫ #== これを、さらに分かり易くするために、    ( ≪ #+ | [^≪≫] | ≫ #-#>= ) の部分を ※ で置き換えると、以下のようになります。    #s ≪ ※ * ≫ #== これは、≪ と ≫ の囲いの中に ※ が 0 回以上あるパターンに一致します。さて、※ の部分には、3分岐がありますが、どの分岐でも、一致するのは1字で、その各場合は、 以下のようになります。   ・≪ に一致する場合、#+ で通過カウントの値が 1 増えます。   ・≪ にも ≫ にも一致しない場合、通過カウントの値は、そのままです。   ・≫ に一致する場合、#- で通過カウントの値が 1 減ります。その際その値が負に     なると、つまり、≪ よりも ≫ の方が多いと、#>= で通過できません。 本正規表現の最後には、#== があるので、 ※ の反復パターンのうち、通過カウントが、 0 になるものしか通過できません。つまり、それは、≪ と ≫ のバランスが取れている パターンに限られます。 ●特別パターン規定  特別パターン規定は、比較的汎用性があるものの、通常の正規表現では表記が煩わしい パターンを、簡易に表記するためのものです。この特別パターン規定の書式は、一般に、    #:<記号>: となります。ここで、<記号> には、各特別パターン規定を示唆する文字が入ります。 この文字は、英数字に限定されているわけではなく、: 以外の任意の文字が使われます。 本章の初節で示した通り、特別パターン規定には、現状、以下があります。   #:(): #:{}: #:[]: #:<>: #:'': #:"": #:/*: #://: #:cw: #:(): と #:{}: と #:[]: は、  それぞれ、丸括弧、波括弧、角括弧の囲い範囲に一致します。この囲いは、入れ子状に  なっているものも含んでいて、必ず、左右の括弧のバランスが取れています。例えば、  #:(): は、「A(B(C(D)E)F(G 」と照合すると、「(C(D)E)」の部分と一致します。  #:{}: は、「A}B}C{D{E}F}G 」と照合すると、「{D{E}F}」の部分と一致します。  #:[]: は、「A[B[C]D[E]F]G 」と照合すると、「[B[C]D[E]F]」の部分と一致します。 #:<>: は、  < と > で囲まれた範囲に一致します。但し、この囲いは入れ子を含みません。これは、  HTML のタグと一致しますが、それ以外(囲い内が、空/空白等)でも一致します。 #:'': と #:"": は、  それぞれ、C 言語系の1重引用符で囲われた文字リテラルと、2重引用符で囲われた  文字列リテラルに一致します。いずれも、\ のエスケープが配慮されていています。  なお、引用符が閉じないまま改行されていると、そこで一致しないと判断されます。 #:/*: と #://: は、  それぞれ、C 言語系のブロックコメント( /* から */ までの範囲 )と、行コメント  ( // から行末までの範囲 )に一致します。なお、どちらのコメントも、入れ子には  なりません。 #:cw: は、  C 言語系の識別子に一致します。これは、以下の正規表現と同じです。    \<[_A-Za-z][_A-Za-z0-9]*\> または \<[_\a]\w*\>  特別パターン規定が対象とするパターンは、本規定を使わない正規表現でも表わせます が、本パターン専用の検索機構が予めシステムに組み込まれているので、本規定を使って 検索する方が、はるかに高速で、メモリーの使用量が少なくて済みます。 ●文法の要約  本章の最初の節の最後で「各規定項の文法的関係」を示しましたが、本節では、まず、 そこで使っている文法規則の表記について、簡単に説明します。   X:     A     B は、「X は、A または B」であることを意味します。   X:     A B は、「X は、A と B 」である、つまり、「A の次に B が続く」ことを意味します。   X:     A     X A は、「X は、A または X と A」ということですが、さらに、展開すると、   「X は、A または 「A または X と A」 と A」   「X は、A または 「A または 「A または X と A」と A」と A」    ・・・・・ となりますが、もう少し分かりやすく表現すると、   「Xは、A または AA または AAA または ・・・ 」 つまり、X は、A が1回以上続くものだということです。 これらを組み合わせて、   X:     A     X B A では、「X は、A または ABA または ABABA または ・・・ 」となります。 最初の正規表現の文法規則は、   正規表現:     連接部     正規表現 | 連接部 でしたが、この意味するところは、「正規表現」とは、   連接部   連接部 | 連接部   連接部 | 連接部 | 連接部   ・・・・・・ のどれかであることを意味します。つまり、1つ以上の「連接部」が「|」で区切られて 続いているものだというです。 2番目の正規表現の文法規則は、   連接部:     連接単位     連接部 連接単位 でしたが、この意味するところは、「連接部」とは、1つ以上の「連接単位」が連続する ものだということです。 3番目の正規表現の文法規則は、   連接単位:     単項     反復項     ≪空≫ でしたが、この意味するところは、「連接単位」とは、「単項」または「反復項」または ≪空≫ だということです。ここで、≪空≫ というのは何も無くても良いということです。 従って、「連接部」は ≪空≫ でも良いということです。ということは、「正規表現」も ≪空≫ でも良いということです。 4番目以降の正規表現の文法規則も、同様です。  なお、以下の項は、その中に「正規表現」を含むので、ここで明記しておきます。この 「正規表現」は、最初の文法規則で示されているものです。   <グループ>:     ( 正規表現 )     @ ( 正規表現 )     @ = ( 正規表現 )   <先読み位置規定>:     # ( 正規表現 )     # ^ ( 正規表現 )  以上述べた文法規則は、各項間の結合力の強さを暗に示しています。例えば、    AB|C+ という正規表現は、以下のようにその構造が解釈されます。   → <通常文字> <通常文字> | <通常文字> +   → 反復可能項 反復可能項 | 反復可能項 反復子   → 単項 単項 | 反復項   → 連接単位 連接単位 | 連接単位   → 連接部 | 連接部 従って、各項間の結合力は、以下の順で、強 → 弱 になります。   (1) 「反復可能項」と「反復子」 ( 例では、C と + )   (2) 「連接単位」と「連接単位」 ( 例では、A と B と C+ )   (3) 「連接部」と「|」      ( 例では、AB と | と C+ ) ●直記文字列での正規表現  正規表現を直記文字列で表わす場合、いろいろと便利なこともありますが、注意すべき こともあります。  まず、注意すべきことについて述べます。正規表現のメタ文字 # と \ を、直記文字列 内で使う場合、各種の制約を気にしないといけません。そのため、これらのメタ文字は、 無条件に、他の文字に代替した方が無難です。例えば、正規表現の最初で、    @%%` としておけば、これ以降、メタ文字の # は % で、\ は ` で代替されるので、# と \ を、 直記文字列内専用の機能に限定して使えます。また、% と ` は、直記文字列内で特別な 機能はないので、正規表現のメタ文字専用に使えます。但し、正規表現内で、% と ` を 通常文字として頻繁に使う場合は、他の文字に代替した方がよいでしょう。  次に、便利なことについて述べます。それは、直記文字列内では、マクロとスクリプト 式が使えるということです。また、直記文字列内では、タブや改行が自由に使えるので、 正規表現で空白を無視するモード( #s あるいは、上記代替の場合 %s )にしておけば、 そこそこ見易い表記にできます。また、直記文字列内では、コメントを入れることもでき ます。なお、どの文字列リテラルでも連続表記ができるので、その間にコメントを入れる ことはできます。  以上のことを踏まえて、直記文字列で正規表現を記述する例を、以下に示します。
    #set    空白列      1
    #set    数字列      2
    #set    英字列      3
    #set    その他      4

    etc = $"(.|`n)";

    Regex = ##@%%`%s        #- メタ文字 # → %  \ → `, 空白無視
        `s+     %#空白列    |
        `d+     %#数字列    |
        `a+     %#英字列    |
        ${etc}  %#その他
    ##;
この例の正規表現は、対象のテキストを、空白列、数字列、英字列、その他の字句要素に 分解するためのものです。これは、「一致パターン識別値」の節で示した CmdLineRegex と同様の使い方ができます。ちなみに、この例の正規表現を、純粋文字列リテラルで記述 すると、以下のようになります。
    Regex = $"\s+#1|\d+#2|\a+#3|(.|\n)#4";
この場合には、この方が、若干見難いものの、簡単になります。しかし、もっと本格的な 字句解析では、字句要素数も多く、正規表現も複雑になるので、直記文字列で正規表現を 記述するメリットが顕著になります。 ●正規表現の文法エラー識別ビット  正規表現に文法エラーがあるかどうかは、    ・システム組み込みリレー型関数 'match で確認することができます。この関数は、主に、対象の文字列と正規表現の照合を行ない ますが、対象の文字列の指定がない場合、正規表現の設定(登録)だけを行なって、その 正規表現の文法エラーを示す下記の値を返します。  正規表現の文法エラーを示す値は、以下のようなビット構成になります。    Bit-0   丸括弧の対応がとれていない    Bit-1   モード指定の # に続く文字が不正    Bit-2   参照指定の @ に続く文字が不正    Bit-3   反復回数指定 {...} の記述が不正    Bit-4   反復対象が不正    Bit-5   文字集合 [...] の記述が不正    Bit-6   先読み位置規定の #^ に続く文字が不正    Bit-7   グループ照合の @[n] の記述が不正    Bit-8   通過カウント演算の記述が不正    Bit-9   特別パターン規定の記述が不正    Bit-10  文字コード指定 \Xnnnn, \Jnnnn の値が不正    その他のビットは、全て 0 です。 ●各種正規表現例 一般文書:  ・空白だけの行    ^[ \t]*(\n|$)  ・行頭の空白部    ^[ \t]+  ・行末の空白部    [ \t]+$  ・ABC を含む行    ^.*ABC.*$  ・ABC を含まない行  ^(#^(ABC).)*$ C言語関連:  ・整数        #i(\d+|0x[0-9A-F]+)U?L?  ・浮動小数点数    #i(\d+\.(\d*)?|\.\d+)(E[-+]?\d+)?[FL]?  ・マクロ       ^[ \t]*\#[ \t]*#:cw:  ・ラベル       ^\s*@=(#^(default\>)#:cw:\s*:)[^:]  そのほかは「特別パターン規定」参照。 インターネット関連:  ・HTMLタグ    #m<[/!]?\a+[^>]*>  ・コメント      #m<!--.*--\s*>  ・URL       [\a\d.+-]+://[\a\d$\-_.+!*'(),:@&=;?%/]+  ・メールアドレス   #i\<(mailto:)?[-\w]+\@[-\w.]+  ・IPアドレス    @(\d{1,3})\.@[1]\.@[1]\.@[1]  ・文字実体参照    &(\#\d+|\a+);  《注意》これらは、厳密に仕様通りにすると複雑になりすぎるので、      適当な実用レベルで留めています。 その他:  ・Windowsファイル名  [^\\/:,;"<>|*?\x00-\x1F\n]+  ・Windowsファイルパス (\a:)?[\\/]?@([^\\/:,;"<>|*?\x00-\x1F\n]+)([\\/]@[1])*