SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

シェルスクリプトマガジン コラボレーション連載/「シェル芸」に効く GNU AWK処方箋

正規表現がもっと使える! 直感的にも使いやすくなった最新GNU AWKの拡張機能を知る

► 「シェル芸」に効く GNU AWK処方箋 第1回 (月刊『シェルスクリプトマガジン 2014 October (Vol.18)』より転載)


length関数の扱い

 何年も前の話ですが、GNU AWKを広めたものにjgawk(Japanized GNU AWK)というものがあります。当時、GNU AWKのlength関数はバイト数を返していました。そこで、jgawkではjlengthという文字数を返す関数を導入することで日本語に対応していました。

 同様な対応がGNU AWKのlength関数でも行われ、GNU AWKのlength関数はバイト数ではなく文字数を返すように変更されています。

$ echo "あいう" | gawk '{print length($0)}'
3

 これは非常に便利なのですが、AWKの得意とすると言われている文書整形で日本語の折り返しを行うには文字数と文字幅が必要になります。残念ながら、これを解決できる手法をGNU AWKは持ち合わせていません。多くのLinuxでは文字コードの標準をUTF-8としたため、表示する文字幅はAWKのような処理系だけではなく表示する端末側にも依存してしまいます。そのため、最適な落としどころが見つかっていません。

 もちろん、この文字単位の扱いはlength関数だけでなく、他の全ての関数にも当てはまります。substr関数の例を以下に示します。

$ echo "あいう" | gawk '{print substr($0, 2, 1)}'
い

引数版 match関数

 GNU AWKでは互換性を保つために関数の引数を増やすことで拡張したものがあります。その例がmatch関数です。グルーピングされた正規表現にマッチするものを取り出したい場合に、match関数の第3引数に多次元配列名を指定します。もちろん、第3引数を用いない場合には、今までどおりのmatch関数と同じ挙動を示します。

 ここで文字列universal shell programmingの頭文字を抜き出す例を挙げておきます。

BEGIN {
    str = "universal shell programming";
    match(str, /([^ ]).+[ ]([^ ]).+[ ]([^ ]).+/, parts);
    for (i = 1; i <= 3; i++) {
        printf("%s", toupper(substr(str, parts[i, "start"], parts[i, "length"])));
    }
    print "";
}

 match.awkというファイル名で保存し実行すると、以下のようになります。

$ gawk -f match.awk
USP

 match関数の第2引数の正規表現に注目してください。ここで丸括弧で括りグルーピングしているものをそれぞれ第3引数である多次元配列partsに格納しています。i番目の開始位置がparts[i, "start"]に格納され、長さがparts[i, "length"]に格納されます。

連想配列のfor ~ inでの呼び出し

 GNU AWKでは組込配列PROCINFOに対して設定を行うことで、他に影響を及ぼさずに拡張するという案が取られています。これにより余分な組込変数を増やすことなく拡張がはかられています。

 前回、連想配列の呼び出しでfor ~ inを用いると単にハッシュテーブルの呼び出しになるため、呼び出しの順序を固定することができないという話を書きました。インデックスを文字列としてソートする場合には以下のように組込配列PROCINFOを使って以下のようにします。

BEGIN {
    value_of["Apple"]  = 100;
    value_of["Orange"] = 200;
    value_of["Banana"] = 300;

    PROCINFO["sorted_in"] = "@ind_str_asc";

    for (i in value_of) {
        print i, value_of[i];
    }
}

 この組込配列PROC_INFO["sorted_in"]は先頭の@を除き3つのパートに分かれます。最初がインデックス(ind)なのか値(val)なのか、次が文字列(str)なのか数字(num)なのか、昇順(asc)なのか降順(desc)なのかです。

 したがって、降順の場合には以下のように記述します。

BEGIN {
    value_of["Apple"]  = 100;
    value_of["Orange"] = 200;
    value_of["Banana"] = 300;

    PROCINFO["sorted_in"] = "@val_num_desc";

    for (i in value_of) {
        print i, value_of[i];
    }
}

 test.awkとして保存して実行すると以下のようになり、指定通りに降順になっていることが分かります。

$ gawk -f test.awk
Banana 300
Orange 200
Apple 100

 この組込配列PROCINFO["sorted_in"]が導入される以前に、配列の値をソートして配列として代入するasort関数とインデックスをソートして配列として代入するasorti関数が導入されました。

BEGIN {
    value_of["Apple"]  = 100;
    value_of["Orange"] = 200;
    value_of["Banana"] = 300;

    asorti(value_of);

    for (i in value_of) {
        print i, value_of[i];
    }
}

 実行例を以下に示します。

$ gawk -f test.awk
1 Apple
2 Banana
3 Orange

 asort関数は元の連想配列の値を通常の配列としてソートした形で格納し、asorti関数は元の連想配列のインデックスを通常の配列としてソートした形で格納するため、連想配列を操作するには扱いにくい関数です。今回の組込配列PROCINFO["sorted_in"]の導入で随分扱いやすくなったのではないでしょうか。

まとめ

 GNU AWKの拡張は一言で言えば「人の直感」に近い拡張です。特にシステムの根幹で昔から動作しているAWKプログラムが多くあるため、互換性に注意して開発されています。そのため、match関数のように追加の引数を導入したり、組込配列PROCINFOを導入し、今まで動作しているプログラムに影響を及ぼさないように開発が進められています。特にa-zやA-Zのような文字集合を示す正規表現の拡張は他のGNUのツールに対してどのような影響を与えるか注目です。

『シェルスクリプトマガジン 2014 November(Vol.19)』は、ただいま絶賛発売中!

シェルスクリプトマガジン 2014 November(Vol.19)

『シェルスクリプトマガジン』は日本で唯一のシェルスクリプト総合誌(毎月25日発売)。最新号 2014 November(Vol.19)の巻頭特集は特別対談「熟年エンジニア2人が語る 若手エンジニアに伝えたいこと」。エンジニアにもっと幸せになってもらいたい、それには何が必要か。過去・現在・未来の視点からこれまでとこれからのITについて語っていただきました。平さんの「リナ女のたしなみ」では、Amazon Glacierを利用した、写真のバックアップを紹介。長谷川さんの「うにっくすなやつら」もシェルスクリプトネタでゆるふわ復活です! 本連載「GNU AWK処方箋」の第2回はレイアウトを一新。たくさんのオオウミガラスと共にGNU拡張された関数を盛りだくさんの内容で解説します。他にも「ユニケージ開発手法 コードレビュー」や「漢のUNIX」など好評連載中です!

► お求めは、Amazon.co.jpUSP研究所のWebサイト取り扱い書店まで。

シェルスクリプトマガジン 2014 November(Vol.19)

価格:500円+税
仕様:B5版 64ページ オールカラー
発行人:ユニバーサル・シェル・プログラミング研究所

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
シェルスクリプトマガジン コラボレーション連載/「シェル芸」に効く GNU AWK処方箋連載記事一覧

もっと読む

この記事の著者

斉藤 博文(サイトウヒロフミ)

最初にAWKと出会ってから○十年、AWKの魅力に取りつかれ、勢い余って「日本 GNU AWKユーザー会」を立ち上げています。会としてOSCなどのイベントにも出展しつつ、GNU AWKの開発も手伝っています。「USP友の会」では幹事役ですが、「シェル芸勉強会」にはほぼ毎回参加して一緒に勉強しています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/8231 2017/01/31 20:07

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー