物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

Python: 正規表現ライブラリを使って、グループ化による置換

以下のような、核種を表す表記を、LaTeXで使えるような表記に置換したい。

He4 → \Nuc{He}{4}{}
He5L → \Nuc{He}{4}{\Lambda}

シンプルなコードだと以下の通り。 グループ化という機能を使って、正規表現側で () で囲むと、囲んだところが \1 \2 と番号が振られるので、それを使って置き換えると良い。 使っている正規表現についてのみ説明しておくと、 [A-Z] で大文字のアルファベット、 [a-z] で小文字のアルファベット ? はその前の文字があるかないか、 \d は数字 {1,3} はその前の文字を1回~3回繰り返す。

import re
print(re.sub(r'([A-Z][a-z]?)(\d{1,3})', r"\\Nuc{\1}{\2}{}", "He4"))
# \Nuc{He}{4}{}
print(re.sub(r'([A-Z][a-z]?)(\d{1,3})L', r"\\Nuc{\1}{\2}{\\Lambda}", "He4L"))
# \Nuc{He}{4}{\Lambda}

ファイル内の全ての核種を表す表記を置き換えてみる。置換が起きなくなるまでループしている。

import re

with open("text.txt",encoding="utf-8") as f:
    lines = f.readlines()
    for i in range(len(lines)):
        while True:
            buf = lines[i]
            lines[i] = re.sub(r'([A-Z][a-z]?)(\d{1,3})L', r"\\Nuc{\1}{\2}{\\Lambda}", lines[i])
            lines[i] = re.sub(r'([A-Z][a-z]?)(\d{1,3})', r"\\Nuc{\1}{\2}{}", lines[i])
            if buf == lines[i]:
                break

with open("text_sub.txt","w",encoding="utf-8") as f:
    f.writelines(lines)

ちなみにtex側はこうしてる。

\newcommand{\Nuc}[3]{$^{#2}_{#3}{\rm #1}$}

f:id:onsanai:20200131085905p:plain