tse - Pythonによるテキスト整形ユーティリティ

  • View
    18.451

  • Download
    0

  • Category

    Career

Preview:

Citation preview

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

ご清聴ありがとうございました

Recommended