主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Python: バイナリデータの条件マッチングに正規表現を使う、あるいは使わない

                
tags: python
 JPEGをいじるライブラリを書いている。そんでJPEGのメタデータ部分に埋め込むサムネイルデータを作るため、JPEGのメタデータ部分から任意のデータを除去しなければならなくなった。

 JPEGのメタデータはセグメントと呼ばれるいくつかのデータブロックから成っている。そのうちで先頭2バイトがb"\xFF\xEn"の値で始まるセグメントをAPPnセグメントと呼ぶ。ちなみにデジカメ写真のメタデータとして有名なExifはAPP1セグメントに入っている。任意のJPEGファイルをサムネイル画像として埋め込めるデータにするためにAPPnセグメントを除去しなければならない。というわけでセグメントわけしたデータの先頭2バイトを判別して、不要なセグメントを除去する。

 先頭2バイトが任意の範囲のあいだにおさまるかの条件判定を、なるべくシンプルに書きたい。まず思い浮かんだやり方は、正規表現を使う。
re.match(b"\xff[\xe0-\xef]", data[0:2])

バイナリだろうと値の範囲指定は問題なくできる。ただ500行のスクリプトでこれ一度のためだけにreモジュールをインポートして使うのもなんかなと思い引っかかっていた。風呂に入っていたら思い浮かんだ。
b"\xff\xe0" <= data[0:2] <= b"\xff\xef"

 Pythonって二つの値の間におさまるかどうかの比較式が書きやすい。正規表現による判定のパフォーマンスコストは低いのであまり問題にはならないだろうが、こっちのやり方はさらにパフォーマンスコストが低い。これでreモジュールのインポートも避けられる。

import re

def isAPPn(data):
return (b"\xff\xe0" <= data[0:2] <= b"\xff\xef")

def isAPPn2(data):
return re.match(b"\xff[\xe0-\xef]", data[0:2])


appn = [b"\xff\xe0\x00\x00", b"\xff\xe5\x00\x00", b"\xff\xe9\x00\x00"]
wrong = [b"\xff\xd9\x00\x00", b"\xff\xf0\x00\x00", b"\xfe\xe0\x00\x00"]


for data in appn:
print(isAPPn(data))

for data in wrong:
print(isAPPn(data))


for data in appn:
print(isAPPn2(data))

for data in wrong:
print(isAPPn2(data))
            

コメントの投稿

非公開コメント

プロフィール

Matoba

Author:Matoba

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。