地底人newbieの気まぐれ

気の向くままに

【仕事効率化】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':'hoge-'})

   # "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':'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":"hoge-",
  "fuga":"fuga~"
}

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

${fuga} is hoge.
   --> "fuga~ is hoge."と出力される
${hoge} is fuga.
   --> "hoge- is fuga."と出力される

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

そのほか

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

まとめ

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