まず入力チェック関数は、すべての数が から までであることと、 同じ数が 2 度以上使っていないかを調べます。
同じものが使われていないかどうかは、少し遅いのですが、 簡単な全数検索をやることにします。 つまり、 番目と 番目 () の数字の比較をすべての と に ついて行います。
for(j=1;j<N;j++) for(k=j+1;k<=N;k++) if(input[j]==input[k]) return -1
すべての数が から までであることのチェックは、
if(input[j]<0 || input[j]>=L) return -1でよさそうな気がしますが、 確実にするならば配列表か、正規表現を利用した方がいいでしょう。
実は、awk は「文字列」と「数字」の区別がなく (明確ではなく)、 状況に応じて適当に変換される、という性質があります。 例えば、「if()」の不等式の部分は、
配列表を利用する方法とは、
for(j=0;j<L;j++) check0[j]=1 # 0~(L-1) のチェックのための配列 for(j=1;j<=N;j++) if(check0[input[j]]==0) return -1という配列は、0 から までの添字に のみ値が 1 と定義されているので、 それ以外の数字、それ以外の文字列に対しては 0 となります。 なお、awk には配列の添字が使われているかをチェックする in という演算子がありますので、それを使って
if(check0[input[j]]==0)の部分は、
if(!(input[j] in check0))と書き直すこともできます。この ``!'' は否定を意味しますから、 「 が、配列 の添字として定義されていなかったら」 という意味になります。
正規表現を使う場合は、例えば以下のような感じになるでしょう。
if(input[j] !~ /^[0-9]$/ || input[j]>=L) return -1正規表現の説明の前に、この文自体を少し説明します。
まず、A||B は A or B を意味します。つまり、「if(A||B) C」 という文は、A が真、または B が真ならば C が実行されます。 C 言語同様、A が真だった場合は B の評価自体が行われませんので、 A||B と B||A とは厳密には少し違います。
A ~ /B/
, A !~ /B/
はいずれもマッチングを調べる演算子で、
A ~ /B/
は A が B にマッチする場合真
A !~ /B/
は A が B にマッチしない場合真
正規表現とは、特別な意味を持つ記号を用いることにより、 複数の文字列を表現するやり方で、主にマッチングで利用されます。 正規表現は、Unix 上の他のツールである sed, (e)grep, perl などでも 利用できますが、 使える表現に少しずつ違い (拡張) があったりします。 awk で使える正規表現については A 節にまとめますが、 ここでは上に使われている正規表現について説明しましょう。
^
= 文字列の先頭を意味する (先頭の文字ではない)
$
= 文字列の最後を意味する (最後の文字ではない) [ ]
= [ ]
内のいずれか 1 文字を意味する
[ ]
内の - =
(ASCII コードが) から までの文字全部を意味する
よって、[0-9]
は、0 から 9 までのいずれか一文字、を意味し、
^[0-9]$
によって、0 から 9 までのいずれか一文字からなる
一文字だけの文字列、を意味することになります。
結局、
if(input[j] !~ /^[0-9]$/ || input[j]>=L) return -1によって、 が 0 から 9 までの いずれか 1 文字でなければ を返す、そうでなくても が 以上ならば を返す、 ということになるわけです。
以上をまとめると、入力のチェック関数は以下のようになります。
function inputcheck(N,L,input, j,k) { for(j=1;j<=N;j++) if(input[j] !~ /^[0-9]$/ || input[j]>=L) return -1 for(j=1;j<N;j++) for(k=j+1;k<=N;k++) if(input[j]==input[k]) return -2 return 0 }