正規表現とパターンマッチング

awk はテキスト処理のツールなので, テキストの構造を記述する厳密な方法を持っている. これを正規表現と呼ぶ. 正規表現について一定の知識を持っていることが, awk でのテキスト処理に不可欠である.

awk では本処理のパターン{アクション} の, パターンを指定するのに正規表現が, よく使われる.

メタキャラクタ

awk のメタキャラクタを挙げれば, 代表的なものは次のようなものである:

. ピリオドは任意の一文字を表す

* 直前の文字の 0 個以上の繰り返しを表す
  [例]
  ab*: a の後ろに b が 0 個以上に続く.
  ab.*: ab の後ろに任意の文字が 0 個以上続く.

+ 直前の文字の 1 個以上の繰り返し
  [例]
  ab+: a の後に b が 1 個以上続く.
  ab.+: ab の後に任意の文字が 1 個以上続く.

^ 文字列の先頭を表す
  [例]
  ^a: 先頭に a が来ることを表す.
  ^ab: 先頭に ab が来ることを表す.

$ 文字列の末尾を表す
  [例]
  a$: 文字列が a で終わることを表す.
  ab$: 文字列が ab で終わることを表す.
  ^$: 空の文字列を表す.

[] [ ] の中の任意の文字を表す
  [例]
  [abc]: a か b か c か を表す.
  [あ-ん]: 全てのひらがな. - で範囲を指定できる.

| 2つの正規表現の選択
  [例]
  ab|cd: ab か cd かを意味する.

() グループ化する
  [例]
  (ab|cd|ef) ab か cd か ef か を意味する.

\ 次に来る文字, それ自体を表す. 通常, メタキャラクタの前につけて,
  そのメタキャラクタとしての意味を打ち消し, 通常の文字として
  扱うことを意味する.
  [例]
  \. ピリオドそのものを表す.
  \\ \ そのものを表す.

パターンマッチングと正規表現

awk の本処理は何度も述べてきたように:

パターン{アクション}

という形式を持っている. パターンの部分は, テキストの特性を記述し, 入力行がその特性を持っているなら, {アクション} を実行する.

テキストがあるパターンを持っているかどうかを試すことをパターンマッチングと言う.

たとえば, 入力行の第 1 フィールドが h という文字で始まるというパターンは, 次のようになる:

$1 ~ /^h/{print}

一つの具体的な例を挙げると, 下のようになる:

[cactus:~/code_py/sphinx]% ls -l | gawk '$9 ~ /^h/ {print}'
-rw-r--r--   1 Wtopia   staff         101 Nov  6 16:30 haskell.rst
-rw-r--r--   1 Wtopia   staff        7325 Nov  3 04:15 haskell.rst~
drwxr-xr-x  66 Wtopia   staff        2244 Nov  3 04:15 html_tuts/

ここで, 半角の ~ は 左辺の文字列が, 右辺の正規表現に適合することを意味する演算子である.

そして !~ を使うと, 左辺の文字列が, 右辺の正規表現に不適合となる.

正規表現には実際に使ってみよう. scpt7.txt というファイルを用意しておこう:

scpt7.txt

apple egg
hat cat
money sky
absent boy
food note
way arrow
foot cap
value dog
home wall
tree sad

下記のスクリプトは, 入力行の 第 2 フィールドが c という文字で始まるというパターンに適合するときだけ実行される.

FNR はファイルの何行目を読んだいるのかを示す. awk の組み込み変数である.

scpt7_1.awk

#!/usr/local/bin/gawk -f
# scpt7_1.awk

$2 ~ /^c/{
    print FNR ":" $2 # 特殊変数 FNR は現在のファイルの入力レコード
}

scpt7_1.awk の実行結果は:

[cactus:~/code_awk/tuts]% ./scpt7_1.awk scpt7.txt
2:cat
7:cap

次は入力行がある文字で終わるかどうかのパターンマッチングの例である.

scpt7_2.awk

#!/usr/local/bin/gawk -f
# scpt7_2.awk

$1 ~ /e$/{ # 第 1 フィールドの単語が e で終わるものを出力
    print FNR ":" $1
}

scpt7_2.awk の実行結果は:

[cactus:~/code_awk/tuts]% ./scpt7_2.awk scpt7.txt
1:apple
8:value
9:home
10:tree

次はパターンを否定表現である.

scpt7_3.awk

#!/usr/local/bin/gawk -f
# scpt7_3.awk

$1 !~ /e$/{ # 第 1 フィールドの単語が e で終わらないものを出力
    print FNR ":" $1
}

scpt7_3.awk の実行結果は:

[cactus:~/code_awk/tuts]% ./scpt7_3.awk scpt7.txt
2:hat
3:money
4:absent
5:food
6:way
7:foot

パターンで, $0 を調べるときには $0 を省略して, 正規表現だけを書くが許される. 次のスクリプトは, $0 すなわち入力全体が “a” で始まる行を出力する.

scpt7_4.awk

#!/usr/local/bin/gawk -f
# scpt7_4.awk

/^a/{ # $0 ~ /^a/ と同じ意味
    print FNR ":" $0
}

scpt7_4.awk の実行結果は:

[cactus:~/code_awk/tuts]% ./scpt7_4.awk scpt7.txt
1:apple egg
4:absent boy

このような正規表現によって, 文字列のパターンを記述し, 実際のテキストがその正規表現に適合するかどうか, すなわち, 正規表現で表されるパターンを持っているかどうかテストすることをパターン・マッチングの例をもう少しあげよう:

/^$/ {print "..."} # 改行だけの空の行を点線に換える

/^[a-zA-Z]+$/ {print} # アルファベットだけの行を出力

/^[a-zA-Z]+/ {print} # アルファベットを 1 文字以上含む行を出力

/^[a-zA-Z \t]+$/ {print} # アルファベットとスペース, タブだけの行を出力

/^[0-9]+$/ {print} # 数字だけの行を出力

/^[0-9\.]+$/ {print} # 数字と小数点だけの行を出力

/^[aA]/ {print} # a か A で始まる行を出力

/^(This|That)/ {print} # This か That という語句で始まる行を出力

Table Of Contents

Previous topic

awk における算術演算

Next topic

文字列関数 (1)