すがブロ

sugamasaoのhatenablogだよ

正規表現したい!

このあつい思いは止められない

あまり C言語正規表現するって聞かないのだけど、もはや正規表現脳なので字句解析に正規表現なしとか考えられない。
なので、必死こいて調べてみた。
以下参考になりそうなサイト

使う流れとしては、まず正規表現オブジェクトを生成し、その後文字列と正規表現オブジェクトの評価を行う。
なんか、こう書くとても当たり前な感じがするが、やってみると意外と面倒。
ちなみに、正規表現の書き方は基本的に ruby や JS と変わらないのだけど、英数字、やスペース等を現す文字列として :xxx: というようなリテラルが用意してある。
たとえば、下記のソースでは>で始まり<で終わる英字を探すようになっている(かつ、括弧でグルーピングしている)。

簡単なソース

  1 /* $Id: regex.c 39 2008-05-19 16:25:42Z sugamasao $ */$
  2 #include <stdio.h>$
  3 #include <stdlib.h>$
  4 #include <regex.h>$
  5 
  6 int main(void) {
  7     char* str = "<p>hoge</p>";
  8     regex_t reg;
  9     regmatch_t* pmatch;
 10     size_t nmatch;
 11 
 12     /* 正規表現オブジェクトの生成 */
 13     if (regcomp(&reg, ">([[:alpha:]].+)<", REG_EXTENDED) != 0) {
 14         puts("正規表現できません><");
 15         return 1;
 16     }
 17 
 18     /* 正規表現格納エリア確保 */
 19     nmatch = reg.re_nsub+1;
 20     pmatch = malloc(sizeof(regmatch_t) * nmatch);
 21 
 22     /* 正規表現実行 */
 23     if (regexec(&reg, str, nmatch, pmatch, 0) != 0) {
 24         puts("見つからなかったよ><");
 25         return 1;
 26     }
 27 
 28     /* 結果出力 */
 29     {
 30         int i = 0;
 31         int j = 0;
 32         for(i = 0; i < nmatch; i++) {
 33             printf("match pattern[%d] = ", i);
 34             for(j = pmatch[i].rm_so; j < pmatch[i].rm_eo; j++){
 35                 printf("%c", str[j]);
 36             }
 37             puts("");
 38         }
 39     }
 40 
 41     free(pmatch);
 42     return 0;
 43 }

このソースを実行した際の結果はこちら

match pattern[0] = >hoge<
match pattern[1] = hoge

解説(できないけど)

一度正規表現オブジェクトを生成すると、生成されたオブジェクト(構造体)の re_nsub というメンバに正規表現としてマッチする個数?(正規表現の個数?)が格納される。
で、それらのマッチを経て、最終形態の正規表現にマッチした形式になるため、 re_nsub + 1 個の正規表現結果を格納する配列を生成しておく。
もちろん、適当に大きな長さの配列を取っておいても良いのだけど、いくつになるのかよくわからないので動的に生成している。
そして、格納する配列やマッチさせる文字列等を引数として regexec に渡すと正規表現が評価されて、結果が格納される。

結果の取り方

まず、結果は regmatch_t 型の配列として取得される。この regmatch_t にはメンバがあり、

  1. rm_so -> マッチ先頭文字数
  2. rm_eo -> マッチ最後尾文字数

が取得される。
したがって、評価対象の文字列の rm_so 番目から rm_eo 番目までを取得する事で文字列を抜き出す事ができる。
そして、この regmatch_t 型の配列の最後尾がパターンマッチの最終形態(よくわからないので、詳しいひと教えて!)が入っているので、
配列の一番最後のオブジェクトを使って文字列を抜き出すと、目的の文字列が抜き出せる(結果で言うところの match patterm[1]の文字列)。

そんなわけで

C言語正規表現するには情報がとても少なくて死にたくなりますね!*1

*1:基本的にはここまで調べた情報で十分だとは思うが・・・