D言語の部屋

[English]


D言語用PCREクラスライブラリ

Introduction

D言語PCRE(Perl Compatible Regular Expressions)を利用できるようにするクラスライブラリを作りました。 このクラスライブラリは、PCREバージョン8.00に付属している C++インタフェースをD言語に移植したものです。

ダウンロード

このパッケージは、"pcrecppd" (PCRE C++ interface for D programming language)と呼びます。最初のアルファバージョンが2010/02/23にリリース されました。

テスト環境

"pcrecppd" は、以下の環境で開発テストされました。

Contributions

このパッケージはまだアルファバージョンですので、皆様からのコメントや パッチは大歓迎です。

使用方法

Import
	pcrecppd を使うために、pcrecppd を import します。

	例:
	   import pcrecppd.pcrecppd;


Matching Interface

       "FullMatch" は、与えられたテキストが指定されたパターンに
       完全に一致するかをチェックします。
       第2引数以降にポインタが与えられたら、パターンにマッチした文字列が
       その引数にコピーされます。

	 例: マッチ成功
	    RE re = new RE("h.*o");
	    re.FullMatch("hello");

	 例: マッチ失敗
	    RE re = new RE("e");
	    !re.FullMatch("hello");


       入力テキストに "string" 型を渡すことができます。
       以下の例では string 型を使っています。

       マッチした文字列を取り出すために、引数にポインタを
       渡さなければなりません。

	 例: "ruby" を "s" に、"1234" を "i" に取り出します。
	    int i;
	    string s;
	    RE re = new RE("(\\w+):(\\d+)");
	    re.FullMatch("ruby:1234", &s, &i);

	 例: 文字列は取り出されません。
	    re.FullMatch("ruby:1234", &s);

	 例: null を与えると文字列を取り出しません。
	    re.FullMatch("ruby:1234", null, &i);

	 例: int のオーバーフローが起き失敗します。
	    !re.FullMatch("ruby:1234567891234", null, &i);


       引数に与えられるポインタは、どんな数値の型でもよく、または、
       以下の型が使えます。

	  string	(マッチした文字列は、string型にコピーされます)
	  StringPiece	(StringPiece は、マッチした文字列を指すようになります)
	  T		(where "bool T::ParseFrom(const char*, int)" exists)
	  null		(対応するパターンにはコピーされません)

       以下の条件を満たすと、この関数は true を返します。

	 a. 入力 "text" が "pattern" に完全に一致する。

	 b. マッチしたパターンの数が、与えた引数の数以上の場合。

         c. "i"番目の引数が "i"番目のマッチしたパターンのデータの型
	    と一致する場合。"i"番目の引数に void* null または
	    voidでない適切な型にキャストした null ポインタを与えるか、
	    マッチしたパターンの数より引数の方が小さい場合、"i"番目の
	    マッチしたパターンは無視されます。

       警告: パターンが文字列に存在しない場合には、空文字列が
       割り当てられます。したがって、以下は flase を返します(なぜなら
       空文字列は有効な数値ではないため)。

	  int number;
	  RE re = new RE("[a-z]+(\\d+)?");
	  re.FullMatch("abc", &number);

QUOTING METACHARACTERS

       文字列中に他の意味に解釈されてしまうような文字がある場合、それらの前に
       バックスラッシュを挿入してくれる "QuoteMeta" 関数があります。
       この関数から返ってきた文字列を正規表現に使うと、
       もともとの文字列と完全に一致します。

	 例:
	    string quoted = RE.QuoteMeta(unquoted);

       文字が正規表現で特別な意味がない場合でも、文字をエスケープしてしまっても
       問題ないことに注意してください。この関数はそれを行います
       (これは、perl の quotemeta 関数と同様の機能です。"perldoc -f quotemeta"
       も見てみてください)。例: "1.5-2.0?" は "1\.5\-2\.0\?" になります。

PARTIAL MATCHES

       テキストの一部の文字にマッチさせたいとき、"PartialMatch" を使います。

	 例: 文字列中の最初に現れる数値を見つける
	    int number;
	    RE re = new RE("(\\d+)");
	    re.PartialMatch("x*100 + 20", &number);
	    assert(number == 100);

UTF-8 AND THE MATCHING INTERFACE

       標準では、パターンも入力テキストもプレーンテキストで、一文字一バイト
       です。UTF8フラグがコンストラクタに与えられると、パターンも
       入力テキストもUTF-8として扱われます。
       実際、パターンよりも入力テキストの方が UTF-8であることが多いですが、
       返されるマッチはUTF8フラグに依存するので、入力テキストがUTF8の時は、
       常にこのフラグを使いましょう。
       たとえば、"."は、通常一バイトにマッチしますが、UTF8フラグが
       セットされると3バイトにまでマッチするかもしれません。

	 例:
	    RE_Options options = new RE_Options();
	    options.set_utf8();
	    RE re = new RE(utf8_pattern, options);
	    re.FullMatch(utf8_string);

	 例: 便利な関数UTF8()の利用例
	    RE re = new RE(utf8_pattern, UTF8());
	    re.FullMatch(utf8_string);

       注意: pcre が --enable-utf8 フラグ付でコンパイルされていなければ、
       UTF8フラグは無視されます。 

PASSING MODIFIERS TO THE REGULAR EXPRESSION ENGINE

       PCREには、正規表現の振る舞いを変更するための修飾子があります。
       Dラッパーには、REクラスにこれらの修飾子を渡すために、
       RE_Options クラスを定義しています。
       現在、以下の修飾子がサポートされています。

	  修飾子		説明			  Perl corresponding

	  PCRE_CASELESS 	case insensitive match	    /i
	  PCRE_MULTILINE	multiple lines match	    /m
	  PCRE_DOTALL		dot matches newlines	    /s
	  PCRE_DOLLAR_ENDONLY	$ matches only at end	    N/A
	  PCRE_EXTRA		strict escape parsing	    N/A
	  PCRE_EXTENDED 	ignore whitespaces	    /x
	  PCRE_UTF8		handles UTF8 chars	    built-in
	  PCRE_UNGREEDY 	reverses * and *?	    N/A
	  PCRE_NO_AUTO_CAPTURE	disables capturing parens   N/A (*)

       (*)  Both Perl and PCRE allow non capturing parentheses by means of the
       "?:" modifier within the pattern itself. e.g. (?:ab|cd) does  not  cap-
       ture, while (ab|cd) does.

       各修飾子がどのように動作するかは、PCRE APIのマニュアルを見てください。

       各修飾子には、二つのメンバ関数があります。
       その名前は、"PCRE_"を削除して小文字にしたものです。
       たとえば、PCRE_CLASSLESS は、
       
	 bool caseless()

       となり、修飾子がセットされていれば、true が返ります。
       そして、

	 RE_Options & set_caseless(bool)

       これは修飾子をセットしたり解除したりします。
       さらに、PCRE_EXTRA_MATCH_LIMIT は set_match_limit()と match_limit()
       メンバ関数からアクセスされます。match_limit を0でない値にすると、
       スタックオーバーフローを起こしたり結果を得るのにとてつもなく長い
       時間がかかるような変なことが起らないようにすることができます。
       値を 500 にすれば、2MBのスレッドスタックでスタックオーバーフローを
       止めることができます。
       match_limit_recursion() を使うと、PCREがどれだけ再帰呼び出しをするかを
       制御することができます。この関数は、PCRE_EXTRA_MATCH_LIMIT_RECURSIONを
       用いています。
       match_limit()はマッチする数を制限します。
       match_limit_recursion()は、内部の再帰の深さ、利用するスタックの量を
       制限します。
       
       通常、複数の修飾子をREクラスに渡すために、RE_Optionsオブジェクトを
       宣言し、さらに適切なオプションをセットし、それをREコンストラクタに
       渡します。たとえば、

	  RE_options opt = new RE_Options();
	  opt.set_caseless(true);
	  RE re = new RE("HELLO", opt);
	  if (re.PartialMatch("hello world")) ...

       RE_options は二つのコンストラクタをもっています。
       標準のコンストラクタは、引数をとらず、フラグは全てオフになっています。
       option_flags というオプションパラメータが従来のCプログラムからの
       移行を容易にするために設けられています。以下のように出来ます。

	  RE_Options opt = new RE_Options(PCRE_CASELESS|PCRE_MULTILINE);
	  RE re = new RE(pattern, opt);
	  re.PartialMatch(str);

       よく用いられる修飾子を引数に渡す際に便利な RE_Options クラスを
       返す関数があります。CASELESS(), UTF8(), MULTILINE(), DOTALL(),
       EXTENDED().

       一度に複数のオプションをセットする必要にあるとき、
       複数の set_xxxxx() メンバ関数を並べると便利です。
       たとえば、PCRE_CASELESS, PCRE_EXTENDED, PCRE_MULTILINE オプションを
       RE に渡す場合、以下のように一行で記述できます。

	  RE_Options opt = new RE_Options();
	  opt.set_caseless(true).set_extended(true).set_multiline(true);
	  RE re = new RE(" ^ xyz \\s+ .* blah$", opt);
	  re.PartialMatch(sometext);


SCANNING TEXT INCREMENTALLY

       文字列のはじめの方から、繰り返し正規表現にマッチさせたいとき、
       "Consume"が便利かもしれません。
       この関数を使うには、"StringPiece"型を使う必要があります。
       この型は、元の文字列の一部の文字列を表現します。
       
	 例: 文字列から、"var = value" という形をした行を読み込みます。
	    string contents = ...;		   // Fill string somehow
	    StringPiece input = new StringPiece(contents);  // Wrap in a StringPiece

	    string var;
	    int value;
	    RE re = new RE("(\\w+) = (\\d+)\n");
	    while (re.Consume(&input, &var, &value)) {
	      ...;
	    }

       "Consume" の呼び出しが成功すると、"var/value"の値をセットし、
       "input" を先に進めます。

       "FindAndConsume" は、"Consume" と似ているが、
       文字列の最初にくさびをうちません。
       たとえば、FIndAndConsume を繰り返し呼ぶことで、文字列から全ての
       単語を取り出します。

	 RE re = new RE("(\\w+)");
	 re.FindAndConsume(&input, &word)

PARSING HEX/OCTAL/C-RADIX NUMBERS

       数値のポインタを引数に渡した場合、標準で、対応するテキストは10進数の
       数値として解釈されます。
       Hex(), Octal(), CRadix()で、そのポインタを囲むことで、異なる進数として
       解釈させることができます。
       CRadix は、C言語表記の "0" (8進数)、"0x" (16進数) を解釈できます。
       標準は10進数です。

	 例:
	   int a, b, c, d;
	   RE re = new RE re("(.*) (.*) (.*) (.*)");
	   re.FullMatch("100 40 0100 0x40",
			Octal(&a), Hex(&b),
			CRadix(&c), CRadix(&d));

       a, b, c, dには、64が入ります。

REPLACING PARTS OF STRINGS

       文字列 "str" 中で、最初に "pattern"にマッチした文字列を "rewrite" に
       置き換えることができます。
       "rewrite" 内に、バックスラッシュでエスケープされた数字 (\1 から \9)を
       書くことで、パターン内のかっこにマッチした文字列を挿入できます。
       \0 は、マッチしたテキストを表しています。
       例えば、

	 string s = "yabba dabba doo";
	 RE re = new RE("b+");
	 re.Replace("d", &s);

       これは、"s" が "yada dabba doo"になります。
       パターンがマッチして置換が行われた場合、trueが返されます。
       他の場合は、falseが返されます。

       GlobalReplace は Replace と似ていますが、文字列内のパターンにマッチした
       全てを置き換えます。
                     
       Replacements are not subject to re-matching. たとえば、

	 string s = "yabba dabba doo";
	 RE re = new RE("b+");
	 re.GlobalReplace("d", &s);

       これは、"s"が "yada dada doo"になります。
       この関数は、置換が行われた回数を返します。

       Extract は、パターンがマッチしたら、"rewrite"が"out"にコピーされて、
       置換が行われます。
       テキストでマッチしなかった部分は無視されます。
       マッチが成功して、抽出が成功したら、trueが返ります。
       マッチが起きなかったら、文字列"s"には何も起きません。

E-mail: Sohgo Takeuchi
Twitter: @sohgo

Sunday, 10-Nov-2013 23:23:40 JST