C++で淡々とregex.hを使ってみた その3

グループを使いつつ, 繰り返しパターンをあててみる.

パターンは最長のものを選んできてしまうので, 短いものが欲しい場合はパターンを工夫する必要がある. 今回はグループ内の文字にセパレータ(ここでは"aeiou"のいずれか)を含まないようにしている.

http://itdoc.hitachi.co.jp/manuals/3020/30203R7651/IMDS0377.HTM

#include <regex.h>
#include <iostream>
#include <string>

int main(void)
{   
    regex_t reg;
    int errcode = regcomp(&reg, "[aeiou]([^aeiou]*)[aeiou]", REG_EXTENDED);
    if (errcode != 0)
    {   
        char errbuf[100]; 
        regerror(errcode, &reg, errbuf, sizeof(errbuf));
        std::cout << "regcompile error: " << errbuf << std::endl;
        regfree(&reg);
        return 1;
    }

    const std::string target("abcdefghijklhmopqrstuvwxyz");
    std::string tmp(target);
    regmatch_t match[2];

    while (true)
    {   
        errcode = regexec(&reg, tmp.c_str(), 2, match, 0);
        if (errcode == REG_NOMATCH)
        {   
            break;
        }
        else if (errcode != 0)
        {   
            char errbuf[100]; 
            regerror(errcode, &reg, errbuf, sizeof(errbuf));
            std::cout << "regexec error: " << errbuf << std::endl;
            regfree(&reg);
            return 1;
        }

        std::cout
            << tmp.substr(match[0].rm_so, match[0].rm_eo - match[0].rm_so)
            << std::endl;
        std::cout
            << tmp.substr(match[1].rm_so, match[1].rm_eo - match[1].rm_so)
            << std::endl;
        tmp = tmp.substr(match[0].rm_eo);
    }
    
    regfree(&reg);
    return 0;
}

今回は2回マッチして,

$ ./a.out
abcde
bcd
ijklhmo
jklhm

のようになるはず. マッチしたパターンはregmatch_t構造体にスタート位置と終了位置(オフセット)がrm_so, rm_eoとして入っているのでこれを使えば良い. コスト的には微妙だがサンプルでは面倒なのでstd::stringを用いた.