No Such Blog or Diary

«Prev || 1 | 2 | 3 | 4 | 5 | 6 | 7 || Next»

sed 再学習

sed は s コマンドしか使えないというのも悲しいので他のコマンドも含めてちゃんと学習しなおす.

とりあえず,sed にはパターンスペースとホールドスペースという二つのバッファがあって,それぞれ改行文字でセグメントという単位に区切られる.s コマンド以外は,これら二つのバッファに対して queue の操作みたいなことを行うか,ラベルへのジャンプをするのが基本.sed の基本的な文法は

「条件」「コマンド」
「条件」「コマンド」
…

で,上から順にパターンスペースが条件にマッチしたらコマンドが実行される.

条件抜粋:

数字
指定行番号
$
最終行である
条件1,条件2
条件1が成立した行から条件2が成立した行まで. ある種のフラグとして利用可能
条件!
条件が成立しない
/正規表現/
正規表現にマッチ

使うコマンドの抜粋:

p
パターンスペースを改行つきで出力
P
パターンスペースの最初のセグメント(改行で区切られたもの)を出力
q
パターンスペースを改行つきで出力して終了
{
次の } までを命令として実行
s/正規表現/文字列/
正規表現にマッチする部分を文字列に置き換える(最初のみ)
s/正規表現/文字列/g
正規表現にマッチする部分を文字列に置き換える(全部)
y/文字列1/文字列2/
文字列1 の各文字を文字列2の対応する文字に置換
d
パターンスペースを削除後に新しい行をパターンスペースに読み先頭へジャンプ
D
パターンスペースの最初のセグメントを削除し先頭に戻る.パターンスペースが空なら次の行を読みこむ
N
一行読みパターンスペースに追加(改行も生きてる)
h
パターンスペースの内容をホールドスペースに読み込む
H
パターンスペースの内容をホールドスペースへ追加
g
ホールドスペースの内容をパターンスペースに読み込む
G
ホールドスペースの内容をパターンスペースに追加
x
パターンスペースとホールドスペースの内容の入れ替え 
b ラベル
ラベルへジャンプ.ラベルなしで先頭へジャンプ
t ラベル
直前の s で置換されたらジャンプ(正規表現条件と s と b で置換可能)
:ラベル
ジャンプ先のラベル
i\ 文字列
文字列を出力.行頭の空白や改行には \ をつける

TIPS:

  • /正規表現/{ 命令列 } という書き方を見ると awk を思い出せる
  • スクリプトの最後にジャンプが無いときは p と d が挿入される
  • s コマンドとかで正規表現が省略されると直前の正規表現が使われる
  • コマンドはセミコロンで区切ると一行で書ける

とりあえず,セグメントに区切って複数のデータを持ち運びつつ,s を使って必要な部分を抜き出して加工すると.何かのアルゴリズムを sed で実装するための導出規則がほしいところだ.

最萌トーナメントの集計スクリプト

AWK の勉強のためとの建前で 第2回東方最萌トーナメント の集計スクリプトを書いてみた.スレッドの番号を入れると wget でページを落としてきて解析して gnuplot でグラフを描いてくれる.あほだ...

ファイルを置いといてみる.

Continue reading

AWK - match と substr

AWK 使いはじめて一時間ほどはまっていたのが,直前の正規表現でマッチした部分の取り出し方だった.ruby やら perl やらではそれらは簡単にできるのだが(特別な変数に入る),awk はそこまではできないらしい.結局 awk で正規表現でマッチした部分を取り出すには,match と substr あたりを使う必要があるとの結論に達した.

例えば, hh:mm 見たいな時間の表示を取り出すには

	pos=match($0, /[0-9][0-9]:[0-9][0-9]/) 
	if(!pos) next
	timestr = substr($0, pos, RLENGTH) 

などのようにする.

match で正規表現をマッチさせて,返り値でその開始位置を取得し(RSTART変数にも入る),長さが RLENGTH に入っているのでその分を substr で取り出すという手順になる.マッチに失敗したときは 0 が帰るらしい.コード中ではマッチしなかった場合に next を呼ぶようにしている.

AWK - はじめ

awk のプログラム(スクリプト)は

pattern { action }
pattern { action }
....

という構造にjなっている.pattern は /regex/ などのような正規表現や,BEGIN, END のような全ての最初と最後を意味するものがある.

入力はレコードセパレータ(RSという変数に入っている)によってレコードに分割され,全ての pattern に対してマッチが取られ,マッチしたときにはその pattern の action が実行される.デフォルトではフィールドセパレータは改行コードなので,一行が一レコードになってる.

例えば,外部から TARGET という変数に何か値を渡してあげて,"Start of TARGET" から "End of TARGET"までのレコードを出力するようなのは以下のとおり.

BEGIN {
	FLAG=0
	STARTPat="Start of "TARGET
	ENDPat="End of "TARGET
}
//{
	if($0 == ENDPat){
		FLAG = 0
	}
	if(FLAG) print
	if($0 == STARTPat){
		FLAG = 1
	}
}

BEGIN で最初に変数を初期化しておいて,その後ろの //{...} で全てのレコードに対してマッチして処理をしている.これをファイル(split.awk)に保存して

awk -f split.awk -v TARGET=1st < in.dat

とかやると, in.dat の中の "Start of 1st" から "End of 1st"までの行が取り出せる.

ちなみにレコードはフィールドセパレータ(FSという変数)で分割されて,各フィールドは $i (i=1,2,...,NF) で取り出せる.$0 はレコード全体.出力は print で,引数を省略すると print $0 の意味になる.

詳しくはマニュアル参照.

«Prev || 1 | 2 | 3 | 4 | 5 | 6 | 7 || Next»
Search
Feeds

Page Top