となりのJohnの気まぐれ

気の向くままに

【仕事効率化】Python3のstring.Templateの破壊力。

f:id:newbie29979:20210130023329p:plain

はじめに

何らかの作業をしているとテンプレートに従って文章を記述する機会がよくある.特に仕事では文章のテンプレートの一部のみを変更して出力することは日常茶飯事である.しかし逐次コピペして一部を変更するのは面倒...

普段からコンピュータを触るものとしてスクリプトでできるだけ簡単に,できるだけ自動化できないだろうか?

幸い,pythonにはこれを実現するための機能がある.string.Templateである.本記事ではこれを用いた自動化について取り上げる.

順に実装を進めていくことで,プログラミング初心者でも追っていきやすい記事をお試しで構成してみる.

動作環境

Python 3.6.9 >=

string.Template

PythonではDictionaryを使った文字列置換関数が用意されている.それがstring.Templateである.string.Templateは以下のように使う.

   text = "${hoge} is fuga."
   template_text = string.Template(text)
   result = template_text.safe_substitute({'hoge':'ほげー'})

   # "ほげー is fuga." と出力される
   print(result)

最低限のコードなので明らかだが,これはsafe_substitute()と合わせて使うことで文字列中の"ある単語"を,与えたkey-valueの値で置換できるようになるものだ.ここから推測されるのは何かしらのテンプレートさえあれば,後は単純にDictionaryの値さえ変えればよいような実装が可能そうなことである.

今回作成するものはテンプレートファイルと定義された辞書を参考に,文章を置換していくスクリプトになる.

テンプレートをファイルから読み込む

より効率的な実装を目指しまずはコード中に文字列を含めるのではなく,テンプレートのファイルから文字列を読み込み置換するようなスクリプトを書く.
pythonのファイル読み込みは以下のように書けばよい.

   with open('template.txt', 'r', encoding='utf-8') as f:
      print(f.read()

今回はこれを応用し,より汎用性の高い実装を目指して,globを使ったファイル読み込みを実装する.スクリプトと同階層にはテンプレートをまとめて管理するTemplatesディレクトリがあり,そのディレクトリ中のtxtファイルを順に読み込み置換していく.

#  -*- utf-8 -*-
import string
import glob


if __name__ == '__main__':
   for template_txt in glob.glob("./Templates/*.txt"):
      with open(template_txt, 'r', encoding='utf-8') as f:
         template_txt = string.Template(f.read())
         result = template_txt.safe_substitute({'hoge':'ほげー'})

         print(result)

テンプレートパターンを増やす

次に,現在の実装では${hoge}というキーワードしか置換できないため拡張する.単純にスクリプト中のDictionaryを拡張すればいいのだが,スクリプトの保守性/拡張性を考えDictionaryについては外部の別ファイルのjsonで記録することにする.jsonファイルはスクリプトと同階層に配置する想定である.
jsonはDictionaryをスクリプト外で管理するのに便利なデータ構造である.詳しくはここを参照すればよい.
以上を反映すると次のようなスクリプトになる.

#  -*- utf-8 -*-
import string
import glob
import json


if __name__ == '__main__':
   vars_dict = {}
   with open("vars.json", 'r', encoding='utf-8') as ref_json:
      vars_dict = json.load(ref_json)
  
   for template_txt in glob.glob("./Templates/*.txt"):
      with open(template_txt, 'r', encoding='utf-8') as f:
         template_txt = string.Template(f.read())
         result = template_txt.safe_substitute(vars_dict)

         print(result)

テンプレートで置換したい単語を定義するjsonはこんな感じ.

{
  "hoge":"ほげー",
  "fuga":"ふが~"
}

このスクリプトは以下のようなテンプレートがあったとき,それぞれ置換後のテキストを出力する.

//テンプレート
${fuga} is hoge.
${hoge} is fuga.

//出力
ふが~ is hoge.
ほげー is fuga.

このようにjsonファイルに退避することで,スクリプトを直接編集せずに済むようにする実装は拡張性の観点からも大事.
実装としてはひと段落したので,あとはテンプレートやそのキーとなる変数名を適当に自分の思うように編集していく.

そのほか

実は以前の記事でこの機能は使っている.
www.rect29.com

まとめ

今回はリポジトリはない.