知人から相談を受けてawkを久しぶりに使う事になりました。

最初はMS-Accessについての相談だったのですが、要件を聞いてみると元ソースはテキストファイル(CSV形式)ですし、Excelのイメージで言うと1つのセルに必要な情報がいくつも入っている状態なので、ExcelやAccessよりもawkで処理した方がスマートだと判断しました。

もっとも、置換機能によって不要な情報削除も必要なので私のスキルではawkだけでは無理でした。おそらくCygwinも入っていないWindows環境で処理されるのでsedも使えません。awk、テキストエディタ(正規表現置換)、sort、uniqの組み合わせで出来るだろうというイメージが出来ました。

sortはWindowsに有るコマンドですが、uniqに関しては無いので作るしか無いですね。もしくはユーティリティーを探してきてuniq抽出するか。

いずれにしても肝となるのは、やはりawkです。awkは簡単に使えて結果が得られる素晴らしい言語ですね。結構古いので廃れてる感はありますが、私的には最も助けてもらっているスクリプト言語です。

さて今回はawkのパターンマッチングを複数回繰り返したいケースのスクリプトの書き方です。別に一個のパターンマッチングを行った結果を、また次のパターンマッチングのソースにするという手順を繰り返せば、極シンプルなスクリプト記述で済むのですが、これがもしルーチンワークとなってくると結構めんどくさい話になってくると思います。

残念ながら私は全てを統合したツール(プログラム)を作るスキルが現在のところ無いので(勉強中である)、集約出来るところはしちゃおうという位の悪あがきしか出来ません。それでも手順が減る方法を知っているのは良い事でしょう。

例えば、ある画像ファイルが沢山あるサイトから、画像ファイルのURLをリストで欲しいと言う課題があるとします。今回はそれが課題です。

手順としては

  1. 当該ページのHTMLファイルをローカルに保存
  2. テキストエディタの置換でタグ(<から>まで)を1行に分解
    具体的には<の前に改行コードを入れれば可能ですね。
  3. awkで画像URLの記述がある行を抽出する
    src="hoge/hoge.jpg"てのがカギになるかな?
  4. awkで画像ファイルの拡張子がある行だけ抽出する
    上記3と4はand条件で実行したいですね。
  5. テキストエディタで行頭から"までを削除
  6. テキストエディタで"から行末までを削除
  7. 相対パス、ルートパス記述に対する保管
  8. sortして重複状況を確認(uniqの事前処理)
  9. uniqで重複行の削除
  10. 最後にゴミ取り(テキストエディタで手作業かな)

いくつかのツールを各手順で使うので、やはり一発で決める(プログラミングする)には現状の私のスキルでは無理です。

上記3.と4.の手順にクローズアップしてみます。awkスクリプトのサンプルを記すと下記の様になります。

BEGIN{
    IGNORECASE = 1;
}
/src=/{
      if ($0 ~ /(jpg|jpeg|gif|png)/) print $0;
}
END{
}

IGNORECASEは大文字小文字を区別する・しないのスイッチです。1にしているので区別しないになり、小文字でも大文字でも正規表現の結果はマッチする様になります。

awkの基本構文ではパターンマッチを1つ記す事が容易ですが、if文を使う事でパターンマッチングを重ねて行うことが可能になります。

/src=/{
      print $0;
}

これが1つ目で、/src=/にマッチしたらその行($0)を出力させてます。

/(jpg|jpeg|gif|png)/{
      print $0;
}

今度はjpg、jpeg、gif、pngにマッチしたらその行($0)を出力させてます。読みやすさでは2つに分けた方がシンプルですが、手間は2度になります。

仮に、このパターンマッチが5回あればどうでしょうか?5個のスクリプトと5回のマッチング作業が必要になります。一発仕事なら良いのですがルーチンワークで毎日やらなきゃならないとかだとウザいですね。

/src=/{
	if ($0 ~ /(jpg|jpeg|gif|png)/){
		if ($0 ~ /special/) print $0;
	}
}

これだと、(1)src=にマッチした後、(2)拡張子が画像にマッチで、(3)special***.jpgという感じ(ファイル名)にマッチした行だけが抽出できます。選択法でどんどん必要な情報だけ抽出する手法ですね。

if文をどんどんネストさせていく方法は、実際のプログラミングではダメだとされていますが、絞り込みオンリーのawkスクリプトでは有りだと私は考えています。なぜならこの単純パターンだけなら、後から見ても目的が一直線の分岐ナシで一目瞭然だからです。

何しろプログラマーでない人がこういう言語を使うには、手法うんぬんよりも結果が第一です。単純パターンでも覚えたら有効な手法ですから使えば良いと私は思っています。

もちろん、この先スキルアップして複雑なスクリプト、またはプログラミングコードを書ける様になった時は控えるべきなのでしょうが。

例外として、学生さんにはこの理屈通用しません。学生さんは理想を目指して苦労して下さい。結果への最短ルートを通る近道よりも、苦労を重ねて理想をさまよい歩く方が将来的にずっと意味があります。社会人オンリーに通用する屁理屈です。くれぐれも学生さんはこういう安易な方法は使わないようにして下さいね(w