[解決済み] 固定幅のファイルを効率的にパースするには?
2023-03-29 02:05:50
質問
固定幅の行を保持するファイルを解析する効率的な方法を見つけようとしています。たとえば、最初の20文字が列を表し、21:30から別の1つのようになります。
行が 100 文字を保持すると仮定して、行をいくつかのコンポーネントに解析する効率的な方法は何でしょうか。
行ごとの文字列スライスを使うこともできますが、行が大きいと少し醜いです。他に高速な方法はありますか?
どのように解決するのですか?
Pythonの標準ライブラリの
struct
モジュールはCで書かれているので、非常に簡単であり、非常に高速です。
以下は、あなたが望むことを行うために使用することができる方法です。また、フィールドの文字数に負の値を指定することで、文字の列をスキップすることができます。
import struct
fieldwidths = (2, -10, 24) # negative widths represent ignored padding fields
fmtstring = ' '.join('{}{}'.format(abs(fw), 'x' if fw < 0 else 's')
for fw in fieldwidths)
fieldstruct = struct.Struct(fmtstring)
parse = fieldstruct.unpack_from
print('fmtstring: {!r}, recsize: {} chars'.format(fmtstring, fieldstruct.size))
line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n'
fields = parse(line)
print('fields: {}'.format(fields))
出力します。
fmtstring: '2s 10x 24s', recsize: 36 chars
fields: ('AB', 'MNOPQRSTUVWXYZ0123456789')
以下の修正により、Python 2または3でも動作するようになります(Unicodeの入力も扱えます)。
import struct
import sys
fieldstruct = struct.Struct(fmtstring)
if sys.version_info[0] < 3:
parse = fieldstruct.unpack_from
else:
# converts unicode input to byte string and results back to unicode string
unpack = fieldstruct.unpack_from
parse = lambda line: tuple(s.decode() for s in unpack(line.encode()))
ここで、あなたが検討していたが、あまりに醜くなるかもしれないと懸念していたように、文字列スライスを使用してそれを行う方法を紹介します。この方法の良いところは、それほど醜くないことに加えて、Python 2 と 3 の両方で変更なく動作し、Unicode 文字列を扱えることです。もちろん、速度的には
struct
モジュールに基づくバージョンよりも遅いですが、パディングフィールドを持つ能力を削除することによって、わずかにスピードアップすることができます。
try:
from itertools import izip_longest # added in Py 2.6
except ImportError:
from itertools import zip_longest as izip_longest # name change in Py 3.x
try:
from itertools import accumulate # added in Py 3.2
except ImportError:
def accumulate(iterable):
'Return running totals (simplified version).'
total = next(iterable)
yield total
for value in iterable:
total += value
yield total
def make_parser(fieldwidths):
cuts = tuple(cut for cut in accumulate(abs(fw) for fw in fieldwidths))
pads = tuple(fw < 0 for fw in fieldwidths) # bool values for padding fields
flds = tuple(izip_longest(pads, (0,)+cuts, cuts))[:-1] # ignore final one
parse = lambda line: tuple(line[i:j] for pad, i, j in flds if not pad)
# optional informational function attributes
parse.size = sum(abs(fw) for fw in fieldwidths)
parse.fmtstring = ' '.join('{}{}'.format(abs(fw), 'x' if fw < 0 else 's')
for fw in fieldwidths)
return parse
line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n'
fieldwidths = (2, -10, 24) # negative widths represent ignored padding fields
parse = make_parser(fieldwidths)
fields = parse(line)
print('format: {!r}, rec size: {} chars'.format(parse.fmtstring, parse.size))
print('fields: {}'.format(fields))
出力します。
format: '2s 10x 24s', rec size: 36 chars
fields: ('AB', 'MNOPQRSTUVWXYZ0123456789')
関連
-
[解決済み] プログラムの実行やシステムコマンドの呼び出しはどのように行うのですか?
-
[解決済み] ファイルのコピー方法について教えてください。
-
[解決済み] 文字列をfloatやintにパースするにはどうしたらいいですか?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
-
[解決済み] python-requests モジュールからのすべてのリクエストをログに記録します。
-
[解決済み] 古いバージョンのPythonにおける辞書のキーの並び順
-
[解決済み] Pythonで0xを使わずにhex()を使うには?
-
[解決済み] virtualenvsはどこに作成するのですか?
-
[解決済み] 新しいpip backtrackingの実行時問題の解決
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] PythonでファイルのMD5チェックサムを計算するには?重複
-
[解決済み] PythonでSVGからPNGに変換する
-
[解決済み] Spyderを仮想環境で動作させるには?
-
[解決済み] django.db.migrations.exceptions.InconsistentMigrationHistory
-
[解決済み] Pythonの要素別タプル演算(sumなど
-
[解決済み] PythonからSMTPを使用してメールを送信する
-
[解決済み] 値で列挙名を取得する [重複]。
-
[解決済み] pandasのタイムゾーンに対応したDateTimeIndexを、特定のタイムゾーンに対応したナイーブなタイムスタンプに変換する。
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] あるメソッドが複数の引数のうち1つの引数で呼び出されたことを保証する