次へ: 6.2 コマンドラインの作成 上へ: 6 各部分の作成 前へ: 6 各部分の作成 (PDF ファイル: awkwww4.pdf)


6.1 ページ数の取得

この節では各部分を実際に作成していきますが、まずは (2) から考えます。 これは、HTML のページ数が書かれている行を抜き出して その情報を取得すればよいのですが、 今回はすべて BEGIN ブロック内だけで入力は仮定していませんから、 明示的に getline を使ってファイルを読みこんで そこから取得することになります。 これを利用すれば、
  fname = "soci-001.html"
  while(getline < fname){
      # $0 に各行が代入される
  }
  close(fname)
のようにして指定したファイルの各行の処理を、 AWK の通常の入力行に対する処理と同じように行うことができます。

今回は、その行の中から

1/6ページを表示(合計123件) ...
のような行を取得すればいいのですが、これを例えば日本語のパターンを使って
$0 ~ /ページを表示/
のようにすることもできなくはありませんが、 このようにすると漢字コード (スクリプトの漢字コード、入力ファイルの漢字コード、および使用している AWK が対応している漢字コード) によってうまくマッチできないことがありますので注意が必要です7

調べてみると、この一覧の HTML ファイルでは ``1/6'' のような文字列が行頭にあるのはこの部分だけのようなので 以下のようなパターンを使って取り出すことにします。

$0 ~ /^[1-9][0-9]*\/[1-9]/
この正規表現は、
[0-9]: 0 から 9 までの数字 1 文字
[0-9]*: 0 から 9 までの数字 0 文字以上の繰り返し
[1-9][0-9]*: 0 以外で始まる 1 文字以上の数字文字列
^[1-9][0-9]*\/[1-9]: 行頭が 0 以外で始まる数字列 + '/' + 0 以外の数字
を意味します。

この行の先頭部分から、 '/' 以降の分母の部分を match()substr() を使って 取り出します。

この行内には「'/' + 数字」の部分はここにしかないようですので、 これを目当てにして以下のようにして取り出します。
  match($0,"/\/[1-9][0-9]*/)
  pages = substr($0,RSTART+1,RLENGTH-1)+0
この substr() の引数ですが、 RSTART+1 は '/' に続く数字列の先頭部分を意味しますし、 '/' を取り除くためにマッチした長さから 1 を引いた RLENGTH-1 を切り出しています。

また、最後の ``+0'' は、変数 pages を数字化するためにつけています。 通常、substr() で切り取ったものは文字列として返されますから、 そのままだと文字列として変数に代入されますが、 ``+0'' という数字演算をつけることで、 その文字列が数字として評価されて代入されることになります。

AWK では、文字列と数字の明示的な区別がなく、 評価されるところで適宜自動的な変換が行われるので、 この変数を次に使用するところが数字演算の中などであれば その時に自然に数字に変換されて使われるので問題はないのですが、 例えば次に使用するところが ``=='' や ``>'' などの 比較演算だとしたら、 これらの演算は文字列も数字も受けつけて、 それぞれで別の評価をしてしまいますので 文字列のままと見なされると誤動作の原因となりえます。

よって、文字列を確実に数字にしたい場合は ``+0'' をつけるのが AWK の常套手段となっています。 逆に数字を確実に文字列にしたい場合は

n = n ""
のように空文字列を連結します8

以上をまとめると、以下のようにすれば pages を取得できることになります。

  ##### pages の取得 #####
  pages = 0
  fname = "soci-001.html"
  while(getline < fname){
      if($0 ~ /^[1-9][0-9]*\/[1-9]/){
          match($0,/\/[1-9][0-9]*/)
          pages = substr($0,RSTART+1,RLENGTH-1)+0
          break
      }
  }
  close(fname)


次へ: 6.2 コマンドラインの作成 上へ: 6 各部分の作成 前へ: 6 各部分の作成
竹野茂治@新潟工科大学
2006年9月29日