このページではJavaScriptを使用しています。

9-6.正規表現パッケージ「鬼車」

9-6-1.概要

「鬼車」は小迫清美氏の開発による正規表現パッケージです。
最新のパッケージは次のURLからダウンロードすることができます。
https://github.com/kkos/oniguruma

9-6-2.ライブラリのインストール

Windows
パッケージにはコンパイル済のDLLライブラリが付属していますが、最新版は前記のURLからダウンロードし、Readmeに従ってコンパイルしてください。
LinuxまたはMac
・前記URLからonigurumaパッケージをダウンロードします。
・解凍、Makeしてインストールします。
$ tar xvf onig-5.9.5.tar.gz
$ cd onig-5.9.5
$ ./configure
$ make
$ sudo make install
$ sudo ldconfig

9-6-3.動作確認

AZ-Prologに付属している動作確認用のプログラムを読み込んで実行します。

Windows
>cd  %AZProlog%¥sample¥ext
>prolog -s oniguruma.pl
| ?- test.
LinuxまたはMac
$ cd ${AZProlog}/share/azprolog/sample/ext
$ prolog -s oniguruma.pl
| ?- test.

9-6-4.使用方法

0.Onigurumaライブラリをロードする

:- dlib_require(oniguruma).

1.正規表現オブジェクトを作成する

onig_pattern_compile(+PATTERN, -REGEX)


PATTERN 正規表現パターン (アトム/文字列)
REGEX 作成された正規表現オブジェクト


不正なパターンを指定すると失敗する。

<例>onig_pattern_compile('^[a-z]+', REGEX).

※正規表現パターンの文法については、以下を参照。
www.geocities.jp/kosako3/oniguruma/doc/RE.ja.txt
これと同じファイルが、インストールしたときの.../oniguruma/doc/RE.jaファイルとして存在するので、これを参照しても良いが、EUC-JPで書かれている。

2.使用しなくなった正規表現オブジェクトを開放する

onig_pattern_free(+REGEX)

たくさん正規表現を使用するのでなければ、実行しなくてもよいかもしれない。

3.不正な正規表現パターンのエラー情報取得

onig_pattern_error_info(+PATTERN, -ERR)

PATTERN 正規表現パターン (アトム/文字列)
ERR エラー情報のアトム


<例>onig_pattern_error_info('(', ERR).
==> ERR = 'end pattern with unmatched parenthesis'

4.検索対象文字列オブジェクトを作成する

onig_make_target_string(+STRING, -TARGET_STRING)

STRING AZ-Prologの文字列(リスト)/アトム
TARGET_STRING 正規表現ライブラリで対象とする文字列オブジェクト


このライブラリはPrologの文字列を直接検索できないので、この述語によって変換したものを作成する必要がある。

改行文字(列)の変換も同時に行われる。
"¥r¥n" ==> "¥n"
31 ==> "¥n" (31: AZ-Prologの改行コード)

対象文字列オブジェクトに対する操作、検索結果のcapture(捕獲)文字列に改行が含まれる場合には、上記の改行コードの変換が行われたものが入っている。

5.検索対象文字列オブジェクトを開放する

onig_free_target_string(+TARGET_STRING)

6.検索対象文字列オブジェクトの一部分を返す

onig_target_string_part(+TARGET_STRING, +START, +END, -PART_STRING)


TARGET_STRING 検索対象文字列オブジェクト
START 開始位置 (先頭は0) バイト単位
END 終了位置 (この位置の文字は含まれない) バイト単位
PART_STRING 部分文字列 (AZ-Prologのリスト)


この述語は検索に直接必要なわけではない。

7.正規表現検索を実行
1)onig_search/7
REGEX 正規表現オブジェクト
TARGET_STRING 検索対象文字列オブジェクト
START 検索開始位置 (先頭は0) バイト単位
END 検索終了位置 (文字列の終わりまでなら未定義でもよい) バイト単位
MSTART マッチした文字列の開始位置 バイト単位
MEND マッチした文字列の終了位置 バイト単位
CAPTURES captureグループ(捕獲式集合)のcapture文字列のリスト

全くマッチしなかった場合には、失敗する。
!!! この述語は非決定性ではない。 !!!

captureグループの中で、マッチしていないグループに対しては文字列ではなく'non'というアトムがセットされる。

<例>正規表現が '(a+)|(b+)'、文字列が "bbbb aaaa"の場合、(b+)のほうにマッチして返るので、(a+)にはマッチしない。
この場合、CAPTURESには、[non, [98,98,98,98]]がセットされる。

2)onig_search_success/8
onig_search_success(+REGEX, +TARGET_STRING, +START, +END, -MSTART, -MEND,
-CAPTURES, -NEXT)

REGEX, TARGET_STRING, START, END, CAPTURES: onig_search/7と同じ。

マッチしたとき
MSTART: onig_search/7と同じ
MEND: onig_search/7と同じ
NEXT: マッチした長さが0より大きいとき
--> MENDと同じ値
マッチした長さが0のとき
--> MENDの次の文字 (次の位置が文字列の範囲外なら、endアトム)

マッチしなかったとき
MSTART: nonアトム
MEND: nonアトム
NEXT: endアトム

!!! この述語は非決定性ではない。 !!!

マッチしなくても失敗しない。
マッチしたとき、次の開始位置を返すので、文字列全体に対して繰り返して実行するとき便利。

※NEXTで、MENDの位置を返すというのは、全てのマッチの可能性を調べるのであれば正しくない。
しかし現実の処理としてはこれで十分。

9-6-5.正規表現パターン文法

1.正規表現パターン基本要素
¥ 退避修飾 (エスケープ) 正規表現記号の有効/無効の制御
| 選択子
(...) 式集合 (グループ)
[...] 文字集合 (文字クラス)
2.文字
¥t 水平タブ (0x09)
¥v 垂直タブ (0x0B)
¥n 改行 (0x0A)
¥r 復帰 (0x0D)
¥b 後退空白
※ 文字集合内でのみ有効
(0x08)
¥f 改頁 (0x0C)
¥a (0x07)
¥e 退避修飾 (0x1B)
¥nnn 八進数表現 符号化バイト値(の一部)
¥xHH 十六進数表現 符号化
¥x{7HHHHHHH} 拡張十六進数表現 コードポイント値
¥cx 制御文字表現 コードポイント値
¥C-x 制御文字表現 コードポイント値
¥M-x (x|0x80) コードポイント値
¥M-¥C-x 超 + 制御文字表現 コードポイント値
3.文字種
. 任意文字 (改行を除く)
¥w 単語構成文字Unicode以外の場合:
英数字, "_" および 多バイト文字。
Unicodeの場合:
General_Category -- (Letter|Mark|Number|Connector_Punctuation)
¥W 非単語構成文字
¥s 空白文字

Unicode以外の場合:
¥t, ¥n, ¥v, ¥f, ¥r, ¥x20

Unicodeの場合:
0009, 000A, 000B, 000C, 000D, 0085(NEL),
General_Category -- Line_Separator
-- Paragraph_Separator
-- Space_Separator
¥S 非空白文字
¥d 10進数字
Unicodeの場合: General_Category -- Decimal_Number
¥D 非10進数字
¥h 16進数字 [0-9a-fA-F]
¥H 非16進数字
Character Property + 全てのエンコーディングで有効
Alnum, Alpha, Blank, Cntrl, Digit, Graph, Lower,
Print, Punct, Space, Upper, XDigit, Word, ASCII,

+ EUC-JP, Shift_JISで有効
Hiragana, Katakana

+ UTF8, UTF16, UTF32で有効
Any, Assigned, C, Cc, Cf, Cn, Co, Cs, L, Ll, Lm, Lo, Lt, Lu,
M, Mc, Me, Mn, N, Nd, Nl, No, P, Pc, Pd, Pe, Pf, Pi, Po, Ps,
S, Sc, Sk, Sm, So, Z, Zl, Zp, Zs,
Arabic, Armenian, Bengali, Bopomofo, Braille, Buginese,
Buhid, Canadian_Aboriginal, Cherokee, Common, Coptic,
Cypriot, Cyrillic, Deseret, Devanagari, Ethiopic, Georgian,
Glagolitic, Gothic, Greek, Gujarati, Gurmukhi, Han, Hangul,
Hanunoo, Hebrew, Hiragana, Inherited, Kannada, Katakana,
Kharoshthi, Khmer, Lao, Latin, Limbu, Linear_B, Malayalam,
Mongolian, Myanmar, New_Tai_Lue, Ogham, Old_Italic, Old_Persian,
Oriya, Osmanya, Runic, Shavian, Sinhala, Syloti_Nagri, Syriac,
Tagalog, Tagbanwa, Tai_Le, Tamil, Telugu, Thaana, Thai, Tibetan,
Tifinagh, Ugaritic, Yi
4.量指定子
欲張り
? 1回または0回
* 0回以上
+ 1回以上
{n,m} n回以上m回以下
{n,} n回以上
{,n} 0回以上n回以下 ({0,n})
{n} n回
無欲
?? 1回または0回
*? 0回以上
+? 1回以上
{n,m}? n回以上m回以下
{n,}? n回以上
{,n}? 0回以上n回以下 (== {0,n}?)
強欲 (欲張りで、繰り返しに成功した後は回数を減らすような後退再試行をしない)
?+ 1回または0回
*+ 0回以上
++ 1回以上

 

({n,m}+, {n,}+, {n}+ は、ONIG_SYNTAX_JAVAでのみ強欲な指定子)

例. /a*+/ === /(?>a*)/

5.錨
^ 行頭
$ 行末
¥b 単語境界
¥B 非単語境界
¥A 文字列先頭
¥Z 文字列末尾、または文字列末尾の改行の直前
¥z 文字列末尾
¥G 照合開始位置
6.文字集合
^... 否定 (最低優先度演算子)
x-y 範囲 (xからyまで)
[...] 集合 (文字集合内文字集合)
..&&.. 積演算 (^の次に優先度が低い演算子)

例. [a-w&&[^c-g]z] ==> ([a-w] and ([^c-g] or z)) ==> [abh-w]
※ '[', '-', ']'を、文字集合内で通常文字の意味で使用したい場合には、これらの文字を'¥'で退避修飾しなければならない。


POSIXブラケット ([:xxxxx:], 否定 [:^xxxxx:])
Unicode以外の場合: alnum
英数字
alpha 英字
ascii 0 - 127
blank ¥t, ¥x20
cntrl  
digit 0-9
graph 多バイト文字全部を含む
lower  
print 多バイト文字全部を含む
punct  
space ¥t, ¥n, ¥v, ¥f, ¥r, ¥x20
upper  
xdigit 0-9, a-f, A-F
word 英数字, "_" および 多バイト文字
Unicodeの場合: alnum
Letter | Mark | Decimal_Number
alpha Letter | Mark
ascii 0000 - 007F
blank Space_Separator | 0009
cntrl Control | Format | Unassigned | Private_Use | Surrogate
digit Decimal_Number
graph [[:^space:]] && ^Control && ^Unassigned && ^Surrogate
lower Lowercase_Letter
print [[:graph:]] | [[:space:]]
punct Connector_Punctuation | Dash_Punctuation | Close_Punctuation |
Final_Punctuation | Initial_Punctuation | Other_Punctuation |
Open_Punctuation
space Space_Separator | Line_Separator | Paragraph_Separator |
0009 | 000A | 000B | 000C | 000D | 0085
upper Uppercase_Letter
xdigit 0030 - 0039 | 0041 - 0046 | 0061 - 0066
(0-9, a-f, A-F)
word Letter | Mark | Decimal_Number | Connector_Punctuation
7.拡張式集合
(?#...) 注釈
(?imx-imx) 孤立オプション
i: 大文字小文字照合
m: 複数行
x: 拡張形式
(?imx-imx:式) 式オプション
(式) 捕獲式集合
(?:式) 非捕獲式集合
(?=式) 先読み
(?!式) 否定先読み
(?<=式) 戻り読み
(?<!式) 否定戻り読み

戻り読みの式は固定文字長でなければならない。
しかし、最上位の選択子だけは異なった文字長が許される。
例. (?<=a|bc) は許可. (?<=aaa(?:b|cd)) は不許可

否定戻り読みでは、捕獲式集合は許されないが、非捕獲式集合は許される。
(?>式) 原子的式集合
式全体を通過したとき、式の中での後退再試行を行なわない
(?<name›式) 名前付き捕獲式集合
式集合に名前を割り当てる(定義する)。
(名前は単語構成文字でなければならない。)

名前だけでなく、捕獲式集合と同様に番号も割り当てられる。
番号指定が禁止されていない状態 (10. 捕獲式集合 を参照)のときは、名前を使わないで番号でも参照できる。

複数の式集合に同じ名前を与えることは許されている。
この場合には、この名前を使用した後方参照は可能であるが、部分式呼出しはできない。
8.後方参照
¥n 番号指定参照 (n >= 1)
¥k‹name› 名前指定参照

名前指定参照で、その名前が複数の式集合で多重定義されている場合には、番号の大きい式集合から優先的に参照される。
(マッチしないときには番号の小さい式集合が参照される)

※ 番号指定参照は、名前付き捕獲式集合が定義され、かつ ONIG_OPTION_CAPTURE_GROUPが指定されていない場合には、禁止される。(10. 捕獲式集合 を参照)

ネストレベル付き後方参照

¥k<name+n> n: 0, 1, 2, ...
¥k<name-n> n: 0, 1, 2, ...

後方参照の位置から相対的な部分式呼出しネストレベルを指定して、そのレベルでの 捕獲値を参照する。

例-1.

/¥A(?<a>|.|(?:(?<b>.)¥g<a>¥k<b+0>))¥z/.match("reer")

例-2.

r = Regexp.compile(<<'__REGEXP__'.strip, Regexp::EXTENDED)
(?<element> ¥g<stag> ¥g<content>* ¥g<etag> ){0}
(? <stag> < ¥g<name> ¥s* > ){0}
(? <name> [a-zA-Z_:]+ ){0}
(? <content> [^<&]+ (¥g<element> | [^<&]+)* ){0}
(? <etag></ ¥k<name+1> >){0}
¥g<element>
__REGEXP__

p r.match('<foo>f<bar>bbb</bar>f</foo>').captures
9.部分式呼a出し ("田中哲スペシャル")
¥g<name> 名前指定呼出し
¥g<n> 番号指定呼出し (n >= 1)

 

※ 最左位置での再帰呼出しは禁止される。
例. (?<name>a|¥g<name>b) => error
(?<name›a|b¥g<name>c) => OK

※ 番号指定呼出しは、名前付き捕獲式集合が定義され、かつ ONIG_OPTION_CAPTURE_GROUPが指定されていない場合には、禁止される。 (10. 捕獲式集合 を参照)

※ 呼び出された式集合のオプション状態が呼出し側のオプション状態と異なっているとき、呼び出された側のオプション状態が有効である。

例. (?-i:¥g<name>)(?i:(?<name>a)){0} は "A" に照合成功する。
10.捕獲式集合

捕獲式集合(...)は、以下の条件に応じて振舞が変化する。
(名前付き捕獲式集合は変化しない)

 

case 1. /.../ (名前付き捕獲式集合は不使用、オプションなし)
(...) は、捕獲式集合として扱われる。
case 2. /.../g (名前付き捕獲式集合は不使用、オプション 'g'を指定)
(...) は、非捕獲式集合として扱われる。
case 3. /..(?<name>..)../ (名前付き捕獲式集合は使用、オプションなし)

(...) は、非捕獲式集合として扱われる。
番号指定参照/呼び出しは不許可。
case 4. /..(?<name>..)../G (名前付き捕獲式集合は使用、オプション 'G'を指定)
(...) は、捕獲式集合として扱われる。
番号指定参照/呼び出しは許可。

但し
g: ONIG_OPTION_DONT_CAPTURE_GROUP
G: ONIG_OPTION_CAPTURE_GROUP
('g'と'G'オプションは、ruby-dev MLで議論された。)

これらの振舞の意味は、名前付き捕獲と名前無し捕獲を同時に使用する必然性のある場面は少ないであろうという理由から考えられたものである。
補記 1. 文法依存オプション
+ ONIG_SYNTAX_RUBY
(?m): 終止符記号(.)は改行と照合成功

+ ONIG_SYNTAX_PERL と ONIG_SYNTAX_JAVA
(?s): 終止符記号(.)は改行と照合成功
(?m): ^ は改行の直後に照合する、$ は改行の直前に照合する
補記 2. 独自拡張機能
+ 16進数数字、非16進数字 ¥h, ¥H
+ 名前付き捕獲式集合 (?‹name›...)
+ 名前指定後方参照 ¥k<name>
+ 部分式呼出し ¥g<name>, ¥g
補記 3. Perl 5.8.0と比較して存在しない機能
+ ¥N{name}
+ ¥l,¥u,¥L,¥U, ¥X, ¥C
+ (?{code})
+ (??{code})
+ (?(condition)yes-pat|no-pat)

* ¥Q...¥E
但しONIG_SYNTAX_PERLとONIG_SYNTAX_JAVAでは有効
補記 4. Ruby 1.8 の日本語化 GNU regex(version 0.12)との違い
+ 文字Property機能追加 (¥p{property}, ¥P{Property})
+ 16進数字タイプ追加 (¥h, ¥H)
+ 戻り読み機能を追加
+ 強欲な繰り返し指定子を追加 (?+, *+, ++)
+ 文字集合の中の演算子を追加 ([...], &&)
('[' は、文字集合の中で通常の文字として使用するときには退避修飾しなければならない)
+ 名前付き捕獲式集合と、部分式呼出し機能追加
+ 多バイト文字コードが指定されているとき、文字集合の中で八進数または十六進数表現の連続は、多バイト符合で表現された 一個の文字と解釈される
(例. [¥xa1¥xa2], [¥xa1¥xa7-¥xa4¥xa1])
+ 文字集合の中で、一バイト文字と多バイト文字の範囲指定は許される。
ex. /[a-あ]/
+ 孤立オプションの有効範囲は、その孤立オプションを含んでいる式集合の終わりまでである
例. (?:(?i)a|b) は (?:(?i:a|b)) と解釈される、(?:(?i:a)|b)ではない
+ 孤立オプションはその前の式に対して透過的ではない
例. /a(?i)*/ は文法エラーとなる
+ 不完全な繰り返し範囲指定子は通常の文字列として許可される
例. /{/, /({)/, /a{2,3/
+ 否定的POSIXブラケット [:^xxxx:] を追加
+ POSIXブラケット [:ascii:] を追加
+ 先読みの繰り返しは不許可
例. /(?=a)*/, /(?!b){5}/
+ 数値で指定された文字に対しても、大文字小文字照合オプションは有効
例. /¥x61/i =~ "A"
+ 繰り返し回数指定で、最低回数の省略(0回)ができる
/a{,n}/ == /a{0,n}/
最低回数と最大回数の同時省略は許されない。(/a{,}/)
+ /a{n}?/は無欲な演算子ではない。
/a{n}?/ == /(?:a{n})?/
+ 無効な後方参照をチェックしてエラーにする。
/¥1/, /(a)¥2/
+ 無限繰り返しの中で、長さ零での照合成功は繰り返しを中断させるが、このとき、中断すべきかどうかの判定として、捕獲式集合の捕獲状態の変化まで考慮している
/(?:()|())*¥1¥2/ =~ ""
/(?:¥1a|())*/ =~ "a"
補記 5. 実装されているが、既定値では有効にしていない機能
+ 捕獲履歴参照
(?@...) と (?@‹name›...)
例. /(?@a)*/.match("aaa") ==> [<0-1>, <1-2>, <2-3>]
使用方法は、sample/listcap.cを参照
有効にしていない理由は、どの程度役に立つかはっきりしないため。
補記 6. 問題点
+ UTF-8で、バイト値が適正な価かどうかのチェックは行なっていない。
* 先頭バイトとして不正なバイトを一文字とみなす
/./u =~ "¥xa3"
* 不完全なバイトシーケンスのチェックをしない
/¥w+/ =~ "a¥xf3¥x8ec"
これを調べることは可能ではあるが、遅くなるので行なわない。