gawk の 3 引数版 match 関数を使う

awk には match 関数というものがあります。 通常の正規表現にマッチしたかどうかを判断する "~" (チルダ) 演算子と異なり、「開始位置」と「マッチした長さ」を変数 RSTART と RLENGTH に格納します。 これを用いることで、ある正規表現にマッチした部分だけを括弧で括るような場合にも使えます。

さて、gawk では match 関数が拡張され、引数を 3 つ取れるようになりました。 最後の引数は配列名を指定しますが、正規表現を括弧でグルーピングした際に、それぞれの開始位置とマッチした長さを個別に格納してくれます。

例えば、以下のように記述します。

#! /usr/local/bin/gawk -f
# match.awk

BEGIN {
    str = "toukyoutokkyokyokakyokukyokakyokutyou"; # 東京特許許可局許可局長
    reg = "(kyo).+(ka)";

    match(str, reg);            # for nawk

    print substr(str, 1, RSTART - 1) "「"                           \
          substr(str, RSTART, RLENGTH) "」"                         \
          substr(str, RSTART + RLENGTH);

    match(str, reg, arr);       # for gawk

    for (i = 1; i <= 2; i++) {
        print substr(str, 1, arr[i, "start"] - 1) "「"              \
              substr(str, arr[i, "start"], arr[i, "length"]) "」"   \
              substr(str,  arr[i, "start"] + arr[i, "length"]);
    }
}

正規表現 reg の "kyo" と "ka" を括弧で括りグルーピングしています。

$ gawk -f match.awk
tou「kyoutokkyokyokakyokukyoka」kyokutyou
tou「kyo」utokkyokyokakyokukyokakyokutyou
toukyoutokkyokyokakyokukyo「ka」kyokutyou

最初の 2 引数版の match 関数では最長一致で正規表現にマッチした区間が区切られていることが分かります。 次の 3 引数版の match 関数では上記のように記述することでグルーピングした正規表現の開始位置とマッチした長さを得ることができます。 n 個目のグループの開始位置は arr[n, "start"] となり、マッチした長さは arr[n, "length"] となります。 RSTART と RLENGTH とは異なる記法になっていますので、注意してください。

また、arr[n] だけで呼び出すと正規表現にマッチした文字列 substr(str, arr[n, "start"], arr[n, "length"]) と同じになります。 こちらは AWK Users JP :: 正規表現記述の順序 でも出ています。

tag_gawk.png