2009/09/10

Qtで言語を作る (4)

 3回目では、正規表現について解説をしました。この表現を使う事で、単語の定義にマッチしているかしていないかが簡単に分かるのでした。

 今回は、について話を進めようと思います。前回の正規表現を使いつつ、テンプレートクラスの使い方も解説します。肝心の文の定義ですが、このようにしたいと思います。

  1. 単語から始まる。
  2. 単語と単語の間は、ホワイトスペースで構成される。
  3. ホワイトスペースは、スペース( ),タブ(\t),改行(\nと\r)の繰り返しで構成される。
  4. 文の最後はピリオド(.)で終わる。

この例を当てはめると、This is very gunjou. のように、各単語の間にホワイトスペースが挿入された文体になります。

 実際にプログラム内部で展開する際には、各単語を抽出し、それが何を意味しているかまで解析をする必要がありますが、今回は単語の抽出迄やる事にします。簡単なアルゴリズムとしては、

  1. ホワイトスペースが表示される迄先頭から検索。
  2. どれかのホワイトスペースが現れたら、先頭から文字を抽出。
  3. 2の位置からホワイトスペースで無い文字が現れる迄検索。
  4. ホワイトスペースで無い文字が現れたら、その位置を先頭とする。
  5. 1-4を繰り返し。

となると思います。きっとループが2つ出来て、分岐もそれなりに出来そうな気がします。更に、抽出した単語をストックしておく為の入れ物も必要になりそうです。挙句の果てに、This is very 群青. とか入力された日には1byte文字以外についても処理出来る様にしなければなりません。

いや、出来ませんって(ioi)。

と思いますが、これを3行でやりましょう。では、サンプルです。

QString s = "This is very gunjou.";
// QStringListはQStringをリストで扱う。
QStringList sl;
// "ホワイトスペースの繰り返し"を正規表現で指定
sl = s.split( QRegExp("(\\s|\t|\r|\n)+") );
s = sl.at( 0 ); // "This"
s = sl.at( 1 ); // "is"
s = sl.at( 2 ); // "very"
s = sl.at( 3 ); // "gunjou."

いかがでしょうか。splitメソッドは、正規表現(でも可)で指定された値を区切りとして、その間にある文字列を抽出しQStringの連結リストを返します。これでコメントと確認用の後ろ4行を抜かせば、実質3行で上記の1-5が出来ました。文字列内の"gunjou"を"群青"にしても正常に動作します(場合によっては文字コードの変換が必要かもしれません)。

 後は、そのリストを順に抽出して確認すれば安心です。確認には3回目の方法を使うとして、連結リストから取り出す方法が必要ですね。以下サンプルです。

foreach( QString t, sl )
{
QRegExp e( "^[A-Za-z_]{1}[A-Za-z0-9_]*$" );
t.contains( e ); // true or false?
}

foreachはコンテナ内のものを(終端迄)一つずつ返し、変数に代入してくれますので、代入された変数にマッチするかしないかの処理を記述します。

 これで無事、文を抽出して単語が正しいかどうかの検証が出来る様になりました。実際には文字列を表す" "の間にあるホワイトスペースの処理が上手く行かないのでコレだけではダメなんですけどね。興味がある方はコチラを参照してみてください(toWordsが今回のものの改良版になります)。


0 コメント:

コメントを投稿

Powered By Blogger