tse - pythonによるテキスト整形ユーティリティ
TRANSCRIPT
tse Text Stream Editor
Python によるテキスト整形ユーティリティ2015/10/10 PyCon JP 2015Atsuo Ishimoto
自己紹介
2
いしもと石本 敦夫あつお
python.jp ドメインの管理者@atsuoishimoto著書
Python ライブラリ厳選レシピPython 文法詳解パーフェクト Python
Unix のテキスト処理といえば
3
sed, awk, perl などのワンライナーが定番Python でもワンライナーを書きたい使い慣れたモジュール群を手軽に活用したいいちいちスクリプトファイルを作成したくないシェルのヒストリーから呼び出したい
4
Python はワンライナー向き?向きません
インデントと改行が必須sys, re などの import など、タイプ量が多いワンライナー用のコマンドラインオプションがない (Python2) Unicode(Encode|Decode)Error$ python -c 'print u" あ "'|less 等。。。
5
tse Text Stream Editor
Python によるテキスト整形ツールPython スクリプトをコマンドラインで指定一般的なモジュール (sys, re など ) の自動インポートファイルを読み込み、スクリプトを実行入出力エンコーディングの指定
6
インストール方法pip install tse
Python2.7 以降Python3.3 以降
7
tse の動作 1 . テキストファイルを一行ずつ読み込み、 2. 行に一致するパターンがあれば、 3. 行を変数に代入し、 4. 対応するアクションを実行する
8
$ tse -s '^\d+' 'print(L.lower())' \ -s '^\w+' 'print(L.upper())'
パターンとアクションパターン 入力行を検索する、正規表現式アクション パターンの検索が成功した時に実行するスクリプト
パターン アクション-s オプションで指定
9
サンプル'spam' を含む行を、小文字に変換して出力tse -s "spam" "print(L.lower())" < s.txt
10
サンプル行ごとに、すべての数字列の和を出力
tse -s ".*" "print(sum(int(s) for s in re.findall(r"\d+", L)))"" < s.txt
11
パターン
例• spam|ham 'spam' または 'ham' を含む行 • ^\d+ 数字列で始まる行
re モジュールを利用入力テキストを検索する正規表現式
12
アクション例• print('hello') 'hello' と出力• print(L.upper()) 行を大文字に変換して出力
パターンがヒットした行で実行するスクリプト
13
複数行のアクション
例$tse -s '^\w' 'if L:' ' print(L)' < spam.txt
パターンには複数のアクションを指定できる。 2 番目以降のアクションは、先頭のアクションの次の行として実行される。
if L: print(a)
14
インデント$ tse -s '.*' 'if len(L)>5:{{print(1)}}'
{{ と }} でインデントするブロックを指定する
if len(L)>5: print(1)
文字列・コメント中の "{{}}" はインデントとして扱わない例 ) 'print("{{spam}}{{ham}}")
15
入力ファイルの指定-s オプションに続けてファイル名を指定するときは、オプションとファイル名を -- で区切る
ファイル名が - のときは、標準入力から読み込む$tse -s '^\d' 'print(S)' -- a.txt b.txt
$tse -s '^\d' 'print(L)' -- -
16
変数処理中のテキストは、変数に格納される変数名 内容L 現在処理中のテキスト行全体L0 テキスト行を空白で区切った文字列
の配列L1, L2,... テキスト行を空白で区切った文字列
の 1 番目、 2 番目、…N L0 の長さ
17
マッチ文字列正規表現にマッチした文字列も変数に格納変数名 内容S 正規表現にマッチしたグループの配列S0 正規表現にマッチした部分文字列全
体S1, S2,... () で囲んだグループの部分文字列グループ名 '(?P< グループ名 >)' で指定したグ
ループの部分文字列M Re モジュールの Match オブジェクト
18
変数のサンプル$ echo 'ab cd ef'| tse -s '.*' 'print(L3, L2, L1)'ef cd ab
空白区切りの単語を出力
$ echo '123abc' \| tse -s '(?P<num>\d+)(.*)' 'print(num, S2)'123 abc
パターンの部分文字列
19
変数のサンプル$ls -l|tse -s '' 'if N>2 and int(L5)>=1024:print(L9)'
サイズ >=1024のファイル名を出力
$ ls -ltotal 168-rw-r--r-- 1 ishimoto staff 698 10 6 12:58 HISTORY-rw-r--r-- 1 ishimoto staff 1064 10 6 12:39 LICENSE-rw-r--r-- 1 ishimoto staff 35 10 6 12:39 MANIFEST.in
1 2 3 4 5 6 7 8 9
20
その他の変数変数名 内容FILENAME 処理中のファイル名。標準入力の場
合は '<stdin>'LINENO 処理中の行番号 (1, 2, 3,…)
21
省略時のパターン
$ tse -s '' 'print(L)'
パターンが空文字列の場合、 '.*' と同じ
$ tse -s '.*' 'print(L)'
22
省略時のアクション
$ tse -s '.*' ''
アクションが空文字列の場合、 'print(L)' と同じ
$ tse -s '.*' 'print(L)'
23
begin アクションと end アクション--begin オプション 起動直後に実行するアクション--end オプション ファイル読み込み終了後に実行するアクション$ tse --begin 's=0' \ --end 'print(s)' \ -s '.*' 's+=len(L)' *.txt
例 ) *.txt ファイル全文字数を出力する
24
インポート済みモジュール$ tse -s '.*' 'os.mkdir(L)'
sys, re, os, os.path はインポート不要
os.path は、 from os import path 形式$ tse -s '.*' 'print(path.splitext(L)[1])'
25
モジュールのインポート--module/-m オプション
実行前にモジュールをインポートする例 ) $tse -m math --begin 'print(math.sqrt(2))'
--module-star/-ms オプションfrom モジュール名 import * 形式でインポートする例 ) $tse -ms math --begin 'print(sqrt(2))'
26
エンコーディング指定--input-encoding/-ie オプション
入力ファイルのエンコーディングを指定する例 ) $tse -ie cp932 -s '' ''
--output-encoding/-oe オプション出力ファイルのエンコーディングを指定する例 ) $tse -ie cp932 -s '' ''
27
--inplace オプション入力ファイルを、出力で上書きする。
$tse --inplace .bak -s '' 'print(L.lower())' -- spam.txt
元のファイルは、指定した拡張子を付加したファイルに保存
28
--script-file/-f オプション起動前に実行するスクリプトファイルを指定する。
$tse -f scr.py -s '' '' < spam.txt
デフォルトでは、 ~/.tserc ファイルが存在すれば実行する。
29
拡張子ごとにファイルサイズ集計$ find . -type f | \tse -ms collections -b 'c=defaultdict(int)' \-s '' 'c[path.splitext(L)[1]]+=path.getsize(L)' \-e 'for r in c.items():print(r)'
30
ip アドレスからホスト名逆引き$ cat log | tse -ms socket -s '' \'try:print(gethostbyaddr(L1)[0], L1)' \'except:print("unknown", L1)'
31
HTML から a 要素を抽出$ curl www.python.jp | tse -ms 'bs4' -b 'for a in BeautifulSoup(sys.stdin.read(), "lxml").find_all("a"):{{url=a.get("href", ""){{}}if url.startswith("http"):print(a["href"])'
32
ご清聴ありがとうございました