そのジャンルの 1 番目の記事、そのジャンルの 2 番目の記事、...のように記事を保存しておく必要があります。 そして記事全体を読み込んだ後で、 それらを各ジャンル毎に出力していくことになります。
つまり、ジャンルが複数存在して、 その各ジャンルに記事が複数存在することになりますが、 そのような記事の保存のために 2 次元配列を利用することにします。
2 次元配列とは、 配列の添え字を 2 次元的に添え字付けられる配列のことを言います。 AWK の配列は連想配列で、元々添え字に文字列も使用できますから、 それを工夫すれば、例えば
a["1x1"], a["1x2"], a["2x1"], a["2x2"], ...のようにして容易に 2 次元配列を作れるのですが、 AWK 自体に 2 次元配列という仕組みが用意されています。
C 言語では、2 次元配列は a[i][j] のように表現しますが、 AWK の 2 次元配列は a[i, j] のように添え字を `,' で区切って 指定することになっています1。
よって、例えば、
a[1,1]=1; a[1,2]=2; a[2,1]="x"; a[2,2]="y";のような使い方ができますし、文字列を添え字にして、
a["abc",3]=3のように使うこともできます。
今回は「
番目のジャンルの
番目の記事」を hs[i,j]
という 2 次元配列に保存することにします。
これを利用すれば、全体の AWK の疑似コードは以下のように書けます。
BEGIN{
# NG = 全ジャンル数
# hn[j] = j 番目のジャンルの記事数 (1<=j<=NG+1)
# ((NG+1) 番目のジャンルは「その他」の記事)
# hs[j,k] = j 番目のジャンルの記事を保存する配列 (1<=k<=hn[j])
#
# (1) j 番目のジャンルのキーワードパターン pat[j] を定義 (1<=j<=NG)
}
($0 ~ /^<h2>/){ title=$0 }
($0 ~ /^<li>/){
# (2) <li> 行から見出し部分だけを取り出す (= str とする)
for(j=1;j<=NG;j++){
if(str ~ pat[j]){
hn[j]++
hs[j, hn[j]]=$0
break
}
}
if(j>=NG+1){ # いずれにもマッチしなかった場合。この場合 j==NG+1
hn[j]++
hs[j, hn[j]]=$0 # 「その他」に保存
}
}
END{
# (3) HTML ヘッダ等の出力
for(j=1;j<=NG+1;j++){
# (4) hs[j,1] ~ hs[j,hn[j]] を出力
}
# (5) HTML フッタ等を出力
}
($0 ~ /^<h2>/) は <h2> で始まる行に対する処理を意味しますが、
これは /^<h2>/ とだけ書いても構いません。
この見出しの行は title という変数に保存していて、
最後のヘッダの出力で利用します。
($0 ~ /^<li>/) のブロックが 各 <li> 行に対する処理ですが、この中で各ジャンルにマッチするかをパターンマッチングを利用して調べています。
正規表現とのパターンマッチングは、通常は
str ~ /正規表現/のように書くのですが、正規表現をあらかじめ変数 (例えば
str ~ patのように書いても同じことになります2。 この場合、変数
str ~ /pat/ とも書きません。
逆に str ~ /pat/ と書いてしまうと ``pat'' という文字列とのマッチングを意味してしまいます。
パターンにマッチした場合には、 そのジャンルに追加するために記事数を一つ増やし (hn[j]++)、 記事をそのジャンルの配列の最後に追加しています (hs[j,hn[j]]=str)。 その場合はそれ以降のマッチングをやる必要がないので break で for 文を抜けだしています。
いずれにもマッチしなかった場合は、for 文のインデックスの
が
になっているはずですから、
それを判別してその
番目のジャンル (「その他」) に保存しています。
なお、for 文の break を next に置きかえれば、 いずれかにマッチすれば for 文の次の文に進むことはなくなりますので、 この for 文の次の if によるチェックは必要ありません。 今回も最終的にはそのように書くことにします。
(3) や (5) のヘッダやフッタの出力は、 [4] や [5] と同様の関数を使って簡単に出力できます。 (2) の部分も、[4] や [5] で述べたように、 sub() などを使って容易に取り出すことができます。 (4) の部分もほぼそのまま並べるだけなので、 よって考えるべき部分は (1) のみ、となります。