次へ: 5.2 入力判定関数 上へ: 5 チェック関数 前へ: 5 チェック関数 (PDF ファイル: awk3.pdf)


5.1 入力チェック関数

今回は、入力されたもののチェック (2 節のルール 4.) と、 結果判定 (2 節のルール 5.) の、 2 つのチェック関数を作成します。

まず入力チェック関数は、すべての数が $0$ から $(L-1)$ までであることと、 同じ数が 2 度以上使っていないかを調べます。

同じものが使われていないかどうかは、少し遅いのですが、 簡単な全数検索をやることにします。 つまり、$j$ 番目と $k$ 番目 ($j<k$) の数字の比較をすべての $j$$k$ に ついて行います。

  for(j=1;j<N;j++)
    for(k=j+1;k<=N;k++)
      if(input[j]==input[k]) return -1

すべての数が $0$ から $(L-1)$ までであることのチェックは、

  if(input[j]<0 || input[j]>=L) return -1
でよさそうな気がしますが、 確実にするならば配列表か、正規表現を利用した方がいいでしょう。

実は、awk は「文字列」と「数字」の区別がなく (明確ではなく)、 状況に応じて適当に変換される、という性質があります。 例えば、「if($A>B$)」の不等式の部分は、

という処理が行われます (cf. [3]、「2-1 パターン」)。 よって、例えば のようになってしまいます。 よって、文字列が入りうる変数に対しては数字との比較を行うのは あまり安全であるとは言えません。

配列表を利用する方法とは、

という性質を利用する方法です。例えば、次のようにします。
  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
$check0[\;]$ という配列は、0 から $(L-1)$ までの添字に のみ値が 1 と定義されているので、 それ以外の数字、それ以外の文字列に対しては 0 となります。 なお、awk には配列の添字が使われているかをチェックする in という演算子がありますので、それを使って
  if(check0[input[j]]==0)
の部分は、
  if(!(input[j] in check0))
と書き直すこともできます。この ``!'' は否定を意味しますから、 「$input[j]$ が、配列 $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||BB||A とは厳密には少し違います。

A ~ /B/, A !~ /B/ はいずれもマッチングを調べる演算子で、

となります。この // で囲まれている部分には正規表現を書きます。

正規表現とは、特別な意味を持つ記号を用いることにより、 複数の文字列を表現するやり方で、主にマッチングで利用されます。 正規表現は、Unix 上の他のツールである sed, (e)grep, perl などでも 利用できますが、 使える表現に少しずつ違い (拡張) があったりします。 awk で使える正規表現については A 節にまとめますが、 ここでは上に使われている正規表現について説明しましょう。

よって、[0-9] は、0 から 9 までのいずれか一文字、を意味し、 ^[0-9]$ によって、0 から 9 までのいずれか一文字からなる 一文字だけの文字列、を意味することになります。 結局、

  if(input[j] !~ /^[0-9]$/ || input[j]>=L) return -1
によって、$input[j]$ が 0 から 9 までの いずれか 1 文字でなければ $-1$ を返す、そうでなくても $input[j]$$L$ 以上ならば $-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
  }


次へ: 5.2 入力判定関数 上へ: 5 チェック関数 前へ: 5 チェック関数
竹野茂治@新潟工科大学
2006年6月8日