Boost.Regex ロシア語正規表現

プーシキン・コンコーダンス・プログラムの新バージョンでは,検索対象語の指定に正規表現を使用できるようにする設計になっている。メタ文字(直前の 0 個以上の文字にマッチする "*" など)を指定した抽象的パターン表現をサポートする。例えば,.*ходить という指定に対し,приходить や подходить など ходить が一致するものすべての語でコンコーダンスを生成するのである。正規表現はプログラミング言語の世界では一般的である。

ロシア語等の Unicode 文字列でも正規表現パターンマッチを支援する C/C++ ライブラリがある。Boost.Regex with ICU である。ICU(International Components for Unicode) は IBM が開発した Unicode ライブラリである。

Unicode の一般的符号化形式である UTF-8 では,ロシア語・キリル文字は 2 オクテットで表現される(漢字の場合は 3 オクテット以上で符号化される)。ここで通常の正規表現ライブラリ(Unicode データ構造を考慮しない通常の Boost.Regex)を用いると,例えば,「任意の一文字」にマッチするメタ文字 "."(ピリオド)について,1 文字が 2 オクテットのキリル文字の検査で不具合が出る。ICU とセットで Boost.Regex を用いると,これがきちんと走査できるのである。しかも簡単。私が書いたテスト・コードを以下に示しておく。もちろん,これ以外にもさまざまな機能があるので,Boost.Regex ドキュメントを参照のこと。

/* -*- coding: utf-8; mode: c++; -*-
 * regex 試験
 */
#include <iostream>
#include <boost/regex.hpp>
#include <boost/regex/icu.hpp>
using namespace boost;
 
int main()
{
    smatch m;   // マッチャー
    u32regex r; // 正規表現パターン
    const char* str1 = "Мой дядя самых честных правил";
    const char* str2 = "правил";
 
    // 試験1
    try {
        r = make_u32regex("честн.*");
    }
    catch (const regex_error& e) {
        std::cerr << "Regex error: " << e.what() << std::endl;
    }
    if (u32regex_search(str1, m, r)) {
        std::cout << "Found (pos=" << m.position() << "): " 
                  << m.str() << std::endl;
    } else {
        std::cout << "Not Found." << std::endl;
    }
 
    // 試験2
    regex_constants::syntax_option_type opt = regex_constants::perl;
    try {
        r = make_u32regex(".*ви.", opt);
    }
    catch (const regex_error& e) {
        std::cerr << "Regex error: " << e.what() << std::endl;
    }
    if (u32regex_match(str2, m, r)) {
        std::cout << "Matched: " << str2 << std::endl;
    } else {
        std::cout << "Not Matched: " << str2 << std::endl;
    }
 
    return 0;
}

boost::u32regex boost::make_u32regex("パターン"); が正規表現パターンの指定である。"パターン" のところに Unicode 文字を使うことができる。検査したい文字列で const char* を初期化し,検査結果を入れるマッチャー boost::smatch を用意して,探索 boost::u32regex_search() やマッチング boost::u32regex_match() などの関数を実行する。対象文字列は const char* 以外もサポートしているが,これがいちばん馴染みがある。こちらでマルチバイト文字 wchar_t* で用意する必要がなく,簡便である。このあたり,Boost ドキュメント Working With Unicode and ICU String Types を参照。

上記のコードをコンパイルするには以下のようにする。Boost / ICU ライブラリを指定しないとリンケージがうまくいかないので注意。

% g++ -L/usr/local/lib -lboost_regex -lboost_system \
-licudata -licui18n -licuuc -g -o regextest regextest.cpp

実行結果は次のとおり。Unicode 文字がきちんと処理できているのがわかる。

% regextest
Found (pos=27): честных правил
Matched: правил