too late amatuar programmer

[python] (比較的)安全にファイル内の文字列を(その場で)置換する

2010-08-03 by ebon | Lavel:

ファイル内の文字列を(その場で)置換したいことは良くある.
単純にファイルを読み込み置換するだけですむなら良いが、やはりできるだけ安全に行いたい.

perlではよく適当に -i オプションを付けて済ませてしまっていたが、
それはどうやら常軌を逸した行いのようだ.
なので少しは誠意ある振る舞いが出来るよう、
(比較的)安全にファイル内の文字列を置換する方法を考え、コードを残しておく.

ほんとに最低限の事だと思うが、安全さを以下のポイントを抑える事で担保する.

ポイント:

  • 一時ファイルに書きだし、それをコピーすることで(その場での)書き込みを行う
  • try ~ finally で元ファイルのcloseは確実に行う

これらをまとめ、以下のコード のように置換を行う関数化しておく.

# -*- coding: utf-8  -*-

import os,re,sys
import tempfile
import shutil

def pat_replace(stext,rtext,file):
    """
    porpose : ファイル内の文字列を(その場で)置換する 
    usage   : pat_replace("置換前パターン","置換後文字列",'target-file') --> replaced file
              * stext は reパターンで渡す必要がある.
    """    
    tmpfd,tmpname = tempfile.mkstemp(dir='.')
    try:
        output_file   = os.fdopen(tmpfd, 'w')
        input_file = open(file)
    except IOError:
        print '"%s" cannot be opened.' % file
    else:
        for line in input_file:
            a = stext.sub(rtext, line)
            output_file.write(a)
    finally:
        output_file.close()
        input_file.close()

    shutil.copyfile(tmpname,file)
    os.remove(tmpname)




ファイルに対しての例外の書き方は以下を参考

にさせていただいた.

Python: ファイル読み込み時の例外の扱い例 - try、except、else、finallyブロック


・・・
自分で書いておいて気になる点が多々ある.
例えば、このコードでは例外を用いいているのが元のファイルを読み込みにかかる時だけだ.
書き出し終わった一時ファイルを元ファイルにコピーする時など、もっと徹底して安全性を持たせる必要があるのだろうか..

また、Dive into Python によると、 try ~ finally よりも、with を使う方が良いみたいだ.

with文は、ファイルを扱うためだけのものではなく、汎用のフレームワークだ。
with文はランタイムコンテキストを作成し、オブジェクトに対して、
ランタイムコンテキストに入ることと出ることを伝える。

とあるが、今のところファイルを扱う以外の用途を浮かばない.想像力が足りないな.
ただこれは、2.6以降からの機能なため、2.5だと使えない..

また、今回のコードは、複数の置換パターンがあった場合、この関数を繰り返し呼ぶなどの方法でしか対応できず、何度もfileをreadする効率の悪いものになってしまう.
ちょうど cook book に、"一度のパスで複数の置換をする"というレシピがあったので、
それを流用し、"(ファイル内の文字列について)一度のパスで複数の置換をする"という
さらに実用的なものにしておきたいと思う.

参考link:
tempfileモジュール
Dive into Python: ファイル
お気楽Pythonプログラミング入門:文字列置換ツールの作成

0 comment:

Post a Comment