複雑なデリミタのデータ加工


アニメ『オーバーロードⅡ』

第1期を見て以来、ずっと続きを待ち望んでました。まさか本当に続編が見れるとは。他のアニメは結構途中から見ても面白いのですが、このアニメは別。最初から見ないと意味が分からないと思います。私もすっかり前作の内容を忘れていたので、もう一度見直しました。いやあ、実に面白い。主人公が悪役って。悪なのに下僕には慈悲深い。いつも怒ってる職場の上司もアニメみて勉強して欲しいです。

前回作った三目並べの結果をもう少し整理したデータにしてみました。

takk@deb9:~$ python tictactoe.py > result
takk@deb9:~$ wc -l result
362880 result
takk@deb9:~$

全部で362880レコードなのは変わりません。
冒頭だけみてみます。

takk@deb9:~$ head result
('O', 7, (1, 2, 3, 4, 5, 6, 7, 8, 9))
('O', 7, (1, 2, 3, 4, 5, 6, 7, 9, 8))
('O', 9, (1, 2, 3, 4, 5, 6, 8, 7, 9))
('O', 9, (1, 2, 3, 4, 5, 6, 8, 9, 7))
('O', 7, (1, 2, 3, 4, 5, 6, 9, 7, 8))
('O', 7, (1, 2, 3, 4, 5, 6, 9, 8, 7))
('O', 9, (1, 2, 3, 4, 5, 7, 6, 8, 9))
('E', 9, (1, 2, 3, 4, 5, 7, 6, 9, 8))
('O', 9, (1, 2, 3, 4, 5, 7, 8, 6, 9))
('E', 9, (1, 2, 3, 4, 5, 7, 8, 9, 6))
takk@deb9:~$

カンマ区切りで、
1列目は、’O’なら○、’X’なら×、’E’なら引き分け。
2列目は、勝敗が決まる手数。例えば、1行目を見ると、7とあるので、7回目に盤上に3つ揃い勝敗が決まります。このデータでは○が7回目に勝ちとなっています。
3列目から行末列までは、盤番号です。

さて本データは、pythonでタプルとリストの複合データをprintしているので、
()がデータに含まれて、テキスト整形のコマンドでは解析しにくいように思えます。

このようなデータでも、各フィールドの意味さえ分かっていれば、整形は簡単です。

各フィールドを抽出するために、不要なデリミタは削除します。この場合は、,(カンマ)以外は不要なので、trで削除します。

takk@deb9:~$ tr -d "'()" < result | head
O, 7, 1, 2, 3, 4, 5, 6, 7, 8, 9
O, 7, 1, 2, 3, 4, 5, 6, 7, 9, 8
O, 9, 1, 2, 3, 4, 5, 6, 8, 7, 9
O, 9, 1, 2, 3, 4, 5, 6, 8, 9, 7
O, 7, 1, 2, 3, 4, 5, 6, 9, 7, 8
O, 7, 1, 2, 3, 4, 5, 6, 9, 8, 7
O, 9, 1, 2, 3, 4, 5, 7, 6, 8, 9
E, 9, 1, 2, 3, 4, 5, 7, 6, 9, 8
O, 9, 1, 2, 3, 4, 5, 7, 8, 6, 9
E, 9, 1, 2, 3, 4, 5, 7, 8, 9, 6
takk@deb9:~$

これでいつものようにcutコマンドが使えるようになりました。

試してみましょう。

takk@deb9:~$ tr -d "'()" < result | cut -d, -f3- | head
 1, 2, 3, 4, 5, 6, 7, 8, 9
 1, 2, 3, 4, 5, 6, 7, 9, 8
 1, 2, 3, 4, 5, 6, 8, 7, 9
 1, 2, 3, 4, 5, 6, 8, 9, 7
 1, 2, 3, 4, 5, 6, 9, 7, 8
 1, 2, 3, 4, 5, 6, 9, 8, 7
 1, 2, 3, 4, 5, 7, 6, 8, 9
 1, 2, 3, 4, 5, 7, 6, 9, 8
 1, 2, 3, 4, 5, 7, 8, 6, 9
 1, 2, 3, 4, 5, 7, 8, 9, 6
takk@deb9:~$

デリミタが特定できれば、awkやperlでもフィルタリングできます。

takk@deb9:~$ tr -d "'()" < result | awk -F, '{print $1,$2}' | head
O  7
O  7
O  9
O  9
O  7
O  7
O  9
E  9
O  9
E  9
takk@deb9:~$
takk@deb9:~$ tr -d "'()" < result | perl -F/,/ -nae 'print "$F[0] $F[1]\n";' | head
O  7
O  7
O  9
O  9
O  7
O  7
O  9
E  9
O  9
E  9
takk@deb9:~$

2列目のデータは、勝敗が決まるまでの手数なので、その後に続く盤のデータは、手数分あれば十分です。余分なデータを削除して整理してみましょう。

Perlで整理。

takk@deb9:~$ tr -d "'()" < result | perl -F/,/ -nae 'foreach(0..(9-$F[1])){pop@F}print"@F\n";' | head
O  7  1  2  3  4  5  6
O  7  1  2  3  4  5  6
O  9  1  2  3  4  5  6  8  7
O  9  1  2  3  4  5  6  8  9
O  7  1  2  3  4  5  6
O  7  1  2  3  4  5  6
O  9  1  2  3  4  5  7  6  8
E  9  1  2  3  4  5  7  6  9
O  9  1  2  3  4  5  7  8  6
E  9  1  2  3  4  5  7  8  9
takk@deb9:~$

awkの方が、すっきり書けるかもしれません。

takk@deb9:~$ tr -d "'()" < result | awk -F, '{for(i=1;i<=$2+2;i++){printf"%s ", $(i)}print "\r"}' | head
O  7  1  2  3  4  5  6  7
O  7  1  2  3  4  5  6  7
O  9  1  2  3  4  5  6  8  7  9
O  9  1  2  3  4  5  6  8  9  7
O  7  1  2  3  4  5  6  9
O  7  1  2  3  4  5  6  9
O  9  1  2  3  4  5  7  6  8  9
E  9  1  2  3  4  5  7  6  9  8
O  9  1  2  3  4  5  7  8  6  9
E  9  1  2  3  4  5  7  8  9  6
takk@deb9:~$

では、データを整理した後の、レコード数を見てみます。

takk@deb9:~$ tr -d "'()" < result | awk -F, '{for(i=1;i<=$2+2;i++){printf"%s ", $(i)}print "\r"}' | sort | uniq | wc -l
255168
takk@deb9:~$

レコード数がずいぶん減りました。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA