Version: 1.0 beta 1
2001年12月20日作成
Copyright © 2001 LangEdge, Inc. All rights reserved.
LEIRegExp.dll は、有限会社ラング・エッジの作成した正規表現ライブラリです。 Windows 用のダイナミックリンキングライブラリの形式をとっています。 本ライブラリは、非商用目的に限り、無料で使用したり再配布したりすることができます。 ライセンスの詳細や商用ライセンスについては、後述します。
本ライブラリは、VC++ で作成したクラスライブラリの形を取っています。したがって、 本ライブラリを使用するためには、クライアントも VC++ を使用する必要があります。
ShiftJIS および EUC コードを用いた日本語文字列に対応しています。 ShiftJIS の場合は、いわゆる半角カタカナも認識します。
正規表現エンジンの形態としては、非決定性有限オートマトン (NFA) 型です。 正規表現を NFA に変換した後、直接それを解釈しながら実行します。DFA 型に比べると、 実行速度では少々劣りますが、使用するメモリ量を抑えることができます。 また、基本的にバックトラックを行わないので、 ほとんどのパターンに対して安定した速度で動作します。
メタ文字を含まない単純なパターン (以降、キーワードと呼びます) の場合は、 Boyer-Moor-Horspool (BMH) アルゴリズムを用いて、高速に検索を行います。また、 キーワードを "|" で結合したパターン (複数キーワードパターン) の場合は、 Aho-Corasick (AC) + BMH アルゴリズムを用いた高速な検索が可能です。
本パッケージには、以下のファイルが含まれています。
| LEIRegExp/ | 本ライブラリ一式をおさめるディレクトリ |
| …/html/ | 本ドキュメント一式をおさめるディレクトリ |
| …/Release/LEIRegExp.dll | 正規表現ライブラリ本体 |
| …/Release/LEIRegExp.lib | クライアントプログラムにリンクされるインポートライブラリ |
| …/include/lei_regexp.h | LEIRegExp.dll のインタフェースを規定するヘッダーファイル。 クライアントプログラムからインクルードする。本ファイルを使用する場合、 コンパイラに与えるマクロとして、DLL_IMPORTING を定義する必要がある |
| …/include/lei_re_util.h | re_util.lib のインタフェースを規定するヘッダーファイル |
| …/include/win_support.h | VC++ の不具合の回避策などを定義したヘッダーファイル |
| re_util/ | LEIRegExp.dll を簡単に使うためのラッパークラスのプロジェクト (ソース付き)。 re_util.lib が作成され、LEIRegExp/Release にコピーされる |
| mygrep/ | LEIRegExp.dll を使用した、簡単な grep プログラムのプロジェクト (ソース付き)。 mygrep.exe が作成され、LEIRegExp/Release にコピーされる |
本ライブラリの提供するクラスや関数は、すべて、 LEIRegExp という名前空間の中で定義されています。
LEIRegExp.dll は、以下のクラスをエクスポートしています。
| LEIRegExp::RegExp | 正規表現の実装クラスへのインタフェースとなるプロキシークラス |
| LEIRegExp::REMatchRange | パターンにマッチした文字列の範囲情報を保持しているクラス |
また、re_util.lib は、以下のクラスや関数を提供しています。
| LEIRegExp::RECache | パターンと、それをコンパイルした正規表現インスタンスとのペアを保存しておくクラス。 正規表現キャッシュ。 後で同じパターンが呼ばれたとき、再コンパイルせずに前回使用したインスタンスを返す |
| LEIRegExp::REMatcher | 正規表現キャッシュを利用してパターンにマッチを行い、 ( ) で指定されるサブパターンにマッチした部分文字列を保持しているクラス |
| LEIRegExp::RegMatch | 正規表現キャッシュのグローバルオブジェクトを利用することにより、 オブジェクト操作を背後に隠して正規表現マッチングを行うことができる関数 |
| LEIRegExp::RegSubst | RegMatch と同様だが、正規表現置換を行うことができる関数 |
本ライブラリは、ShiftJIS および EUC コードを用いた日本語文字列に対応しています。 たとえば、正規表現の . は日本語の1文字にマッチします。あるいは、 ? や + などのクロージャの直前に日本語文字がある場合、 その1文字が繰り返しの対象となります。 ShiftJIS の場合は、いわゆる半角カタカナも認識されます。
デフォルトでは、ShiftJIS が有効になっています (Window版の場合)。 EUC コードをデフォルトの日本語コードに設定したい場合は、 LEIRegExp::RegExp::EUC を引数にして LEIRegExp::RegExp::SetDefaultJCode() 関数を呼び出します。
デフォルトの文字コードにかかわらず、パターンごとに文字コードを指定するには、 LEIRegExp::RegExp::RegExp() や LEIRegExp::RegExp::regcomp() の引数として、 動作指定フラグに LEIRegExp::RegExp::REG_SJIS または LEIRegExp::RegExp::REG_EUC をセットしたものを渡します。
次のバージョンでは、UTF-8 および UTF-16 への対応を予定しています。
以下は、LEIRegExp::RegExp を使用する例です。
// DLL_IMPORTING の定義 (コンパイルスイッチで -DDLL_IMPORTING としてもよい)
#define DLL_IMPORTING 1
#include <iostream>
using namespace std;
// 正規表現のインタフェースを宣言しているファイル
#include "lei_regexp.h"
using namespace LEIRegExp;
int main()
{
// パターンから正規表現インスタンスを作成
RegExp regexp( "foo" );
if (regexp.succeeded()) {
// パターンコンパイルに成功
if (regexp.regexec( "a foo bar", 0 )) {
// パターンマッチに成功
// パターンにマッチした範囲を得る
REMatchRange rm = regexp.getMatchedRange( 0 );
cout << "match: [" << rm.begin << " - " << rm.end << "]" << endl;
}
}
return 0;
}
実行結果は次のようになります。
match: [2 - 5]
以下は、LEIRegExp::RECache を使用する例です。
// DLL_IMPORTING の定義 (コンパイルスイッチで -DDLL_IMPORTING としてもよい)
#define DLL_IMPORTING 1
#include <iostream>
using namespace std;
// 正規表現キャッシュインタフェースを宣言しているファイル
#include "lei_re_util.h"
using namespace LEIRegExp;
int main()
{
// 正規表現キャッシュを作成
RECache reCache;
// とあるパターンと文字列に対してパターンマッチを実行する
// C++ ソースで、直接パターン文字列を記述する場合は、
// \s を指定するのに \\s と書くことに注意
RegExp *pReg = reCache.regMatch( "foo\\s+bar", "hoge foo bar fuga!" );
if ( pReg ) {
cout << "begin: " << pReg->getMatchedRange(0).begin << endl;
cout << "end: " << pReg->getMatchedRange(0).end << endl;
cout << "length: " << pReg->getMatchedRange(0).length() << endl;
}
// pReg を delete してはいけない!
// とあるパターンと文字列に対してパターン置換を実行する
// C++ ソースで、直接パターン文字列を記述する場合は、
// \s を指定するのに、\\s と書くことに注意
string result;
pReg = reCache.regSubst( "/foo/bar/ig", "foo Foo FOO!", result );
if ( pReg ) {
cout << "result: " << result << endl;
}
// pReg を delete してはいけない!
return 0;
}
実行結果は次のようになります。
begin: 5 end: 12 length: 7 result: bar bar bar!
以下は、LEIRegExp::REMatcher を使用する例です。
// DLL_IMPORTING の定義 (コンパイルスイッチで -DDLL_IMPORTING としてもよい)
#define DLL_IMPORTING 1
#include <iostream>
using namespace std;
// 正規表現マッチャーのインタフェースを宣言しているファイル
#include "lei_re_util.h"
using namespace LEIRegExp;
int main()
{
// 正規表現マッチャーを作成
REMatcher matcher;
// とあるパターンと文字列に対してパターンマッチを実行する
// C++ ソースで、直接パターン文字列を記述する場合は、
// \w を指定するのに \\w と書くことに注意
if (matcher.match( "f\\w+o", "hoge foo bar fuga!" )) {
cout << "match: " << matcher[0] << endl;
}
// 文字によるカッコ指定
if (matcher.match( "({a}f\\w+o)\\s+bar", "hoge foo bar fuga!" )) {
cout << "match[0]: " << matcher[0] << endl;
cout << "match[a]: " << matcher['a'] << endl;
}
return 0;
}
実行結果は次のようになります。
match: foo match[0]: foo bar match[a]: foo
LEIRegExp::RegExp::regcomp() などの関数に引数として与えることのできるパターンの仕様は以下のとおりです。
LEIRegExp::RegExp::REG_DELIM を指定しておく必要があります。 この場合、パターンの先頭文字をデリミタとみなします。 デリミタには任意の文字を使用することができますが、 パターン内におけるデリミタ文字は統一されていなければなりません。
例:
regcomp( "/foo.*bar/", 0, RegExp::REG_DELIM ); /* / がデリミタ */
regcomp( ":^...$:", 0, RegExp::REG_DELIM ); /* : がデリミタ */
置換文字列を含むパターンの場合は、引数の動作指定フラグに LEIRegExp::RegExp::REG_SUBST を指定しておく必要があります。 LEIRegExp::RegExp::REG_SUBST は LEIRegExp::RegExp::REG_DELIM の指定も含意しています。
例:
regcomp( "/foo/FOO/", 0, RegExp::REG_SUBST ); /* / がデリミタ */
デリミタが有効になっている場合、パターンの末尾に動作指定フラグを記述することができます。 現在サポートされているフラグは次のとおりです。
i …… 英字の大文字・小文字の違いを無視するg …… マッチングや置換をターゲット文字列の全体にわたって繰り返すm …… 複数行モード。^ や $ が文字列中の任意の改行文字にマッチするp …… カッコで囲まれたサブパターンにマッチする範囲情報を保持する
regcomp( "/(fo*)o/ip", 0, RegExp::REG_DELIM );
本ライブラリでサポートしている正規表現の一覧です。
| 【アンカー類】 (アンカーは、文字と文字の間にマッチする) | |
^ |
行頭にマッチ |
$ |
行末にマッチ。行末が \n ならば、その \n の前の位置にマッチ |
\A |
文字列の先頭にマッチ |
\Z |
文字列の末尾にマッチ。文字列末が \n ならば、その \n の前の位置にマッチ |
\b |
単語境界 (単語構成文字と非単語構成文字との間) にマッチする |
\B |
単語境界以外の文字間にマッチする |
(?= |
文字列を先読みして、pattern にマッチするかどうかを調べる。 もしマッチすれば、その先読み開始位置にマッチ (肯定先読み) |
(?! |
文字列を先読みして、pattern にマッチするかどうかを調べる。 もしマッチしなければ、その先読み開始位置にマッチ (否定先読み) |
| 【アトム類】 (アトムは、1文字にマッチする) | |
| 通常文字 | メタ文字 (^, $, \, .,
[, ], (, ),
?, *, +, {, })
以外の通常文字は、その文字自体にマッチ。
2バイトの日本語文字や1バイトの半角カナ文字も1文字として扱われる |
. |
改行以外の任意の1文字にマッチ |
\a |
アラート文字 (0x07) にマッチ |
\f |
フォームフィード文字 (0x0c) にマッチ |
\n |
改行文字 (0x0a) にマッチ |
\r |
復帰文字 (0x0d) にマッチ |
\t |
タブ文字 (0x09) にマッチ |
\v |
垂直タブ文字 (0x0b) にマッチ |
\nnn |
nnn (n は 0〜7) の8進数でコードが表わされる文字にマッチ |
\xnn |
nn (n は 0〜9, a-z) の16進数でコードが表わされる文字にマッチ |
\d |
'0' から '9' までの数字にマッチ |
\D |
'0' から '9' 以外の文字にマッチ |
\w |
単語構成文字、すなわち、英字、数字およびアンダースコアにマッチ |
\W |
単語構成文字以外の文字にマッチ |
\s |
空白文字 (ブランク、タブ、復帰、改行) にマッチ |
\S |
空白文字以外の文字にマッチ |
[ string ] |
string に含まれる任意の1文字にマッチ。日本語文字も1文字として扱われる。
string 内には、上記の \ によるエスケープ表現および
x-y による文字範囲指定が可能である。
., (, ), ?, *, +, {, }, $ および先頭以外の ^
はメタ文字としての意味を失い、通常の文字の扱いになる
|
[^ string ] |
string に含まれない任意の1文字にマッチ。 string の解釈は、上と同様 |
| 【連接】 | |
| x y ... z | 各表現 x、y、...、z のそれぞれへのマッチが 連続している部分にマッチ |
| 【選択】 | |
x | y | ... | z |
各表現 x、x、...、または z のいずれかにマッチ |
| 【カッコ・リファレンス類】 | |
( pattern ) |
カッコ内の表現 pattern をひとまとめにする。
また、カッコの出現順に対して、1 から順に番号をふっておき、
後で '\数字' という形式のリファレンスを使うことができる。
また、RegExp::getMatchedRange() や REMatcher::operator[]
の引数としてカッコの番号を与えることにより、
カッコ内のパターンにマッチした範囲を得ることができる
|
({n} pattern ) |
表現 pattern をひとまとめにして、カッコに
n (n は、'a'から 'z') という名前を付ける。
後で '${名前}' という形式のリファレンスを使うことができる。
また、RegExp::getMatchedRange() や REMatcher::operator[]
の引数としてカッコの名前 ('a' 〜 'z') を与えることにより、
カッコ内のパターンにマッチした範囲を得ることができる
|
\1 ... \9 |
n (= 1...9) 番目のカッコにマッチしている文字列へのリファレンス |
${a} ... ${z} |
名前 ('a' ... 'z') が定義されているカッコにマッチしている文字列へのリファレンス |
| 【繰り返し指定】 (クロージャ) | |
? |
直前の表現の 0 〜 1回の繰り返しにマッチ。可能なら1回のマッチのほうを優先 |
* |
直前の表現の 0回以上の繰り返しにマッチ。可能な限り最大回数のマッチを優先 |
+ |
直前の表現の 1回以上の繰り返しにマッチ。可能な限り最大回数のマッチを優先 |
{n,m} |
直前の表現の n回以上、m回 (m ≦ 100) 以下の繰り返しにマッチ。 可能な限り最大回数のマッチを優先 |
{n,} |
直前の表現の n回 (n ≦ 100) 以上の繰り返しにマッチ。 可能な限り最大回数のマッチを優先 |
{n} |
直前の表現の n回 (n ≦ 100) の繰り返しにマッチ |
| 【最短マッチ指定】 | |
? |
上記の繰り返し指定の直後に記述する。 繰り返し指定は、通常、繰り返し回数が最大になるようなマッチが優先されるが、 この指定があると、繰り返し回数が最小になるようなマッチが優先される。 |
2つ以上の表現が結合する場合の優先順位は、高いほうから並べると、以下のようになります。
パターンマッチ後に、LEIRegExp::RegExp::getMatchedRange などの関数に 0 以外の引数を渡してサブパターンにマッチしている部分文字列の範囲情報を得ようとすると、 その範囲情報の保持を行うモード (すなわち LEIRegExp::RegExp::REG_PAREN が指定されたモード) で、自動的に再マッチングが実行されます。
もし、サブパターンにマッチした部分文字列の情報を使うことがあらかじめわかっているのであれば、 最初から LEIRegExp::RegExp::REG_PAREN を指定してマッチングを実行することをおすすめします。
{ … } による繰り返し回数指定 {n, m} を使用して繰り返し回数を指定すると、 内部的には、 x x … x (x (x (…)?)?)? └ n個 ┘└─ m-n個 ─┘
という形に展開してしまいます。したがって、m としてあまり大きな数を指定すると、 多大なメモリを使ってしまうことになる可能性があるので、現在、 最大値を 100 に制限してあります。
後方参照
(?= ) や (?! ) の先読みの中では使用することができません。
(……).*(……).*\1…\2
のように、後方参照で指定示されているカッコが複数あって、 その間に .* のような可変長文字列にマッチする表現がある場合は、 バックトラックによる試行回数が膨大な数になる可能性があります。 ご注意ください。
a* のように幅が 0 (になりうる) 表現に対して 繰り返し指定を行うことはできません。
例:
(a*)+
このようなパターンをコンパイルしようとすると、エラーが返ります。
| 当社 | 有限会社ラング・エッジ |
| 本パッケージ | 正規表現ライブラリ LEIRegExp を構成する全ファイル (DLL、ソース、ドキュメントなどすべて) を含む集合体 |
| 当該諸行為 | 本パッケージの全部または一部を使用・複製・配布する行為の全部または一部 |
| 当該諸権利 | 当該諸行為を行う権利 |
| 当該利用者 | 本ライセンスに記述した6条項のすべてを遵守することに同意した個人または組織 |
当社は、当該利用者に対して、本パッケージに関する当該諸権利を許諾します。 当該諸権利の行使に際して、当該利用者は当社を含むいかなる個人あるいは組織に対しても 対価を支払う義務はありません。 以下の 6条項のすべてを遵守することに同意しない個人または組織に対しては、 当該諸権利を許諾しません。
上記ライセンスは、要するに、非商用目的に限り無料で本ライブラリをお使いいただけますよ、 ということを物々しく書いてあるわけです。会社の製品でもあるので、 よろしくご理解ください。
また、商用目的 (シェアウェアなども含む) で本ライブラリを使用したいとお考えの方には、 別途、 有料の商用ライセンスをご案内しています。 いずれは当社の Web サイトを立ち上げて、 そこでご説明したいと考えておりますが、 当面は、私あてにメールをいただければ、 ライセンス料金などのご案内をさせていただきます。