SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

置き換えたい単語の組み合わせが複数ある時に一発でやる方法/Python文法

f:id:arakan_no_boku:20190223210405j:plain

目次

置き換えたい単語の組み合わせが複数ある時に一発でやる方法

例えば、こんな文章があった時。

東京大学大阪大学では社会人向けの「AI講座」を開いている。
また経済産業省は「AIプログラム技術」や課題解決を企業や学生らが教え合う「AI学校」を9月にも立ち上げる。
実務経験を積んだ人材が互いに鍛え合い、専門人材を育成する。

「AI学校」は「AIスクール」、「AIプログラム技術」は「AIスキル」、「AI講座」は「AIクラス」などマッチする単語によって別の単語に置き換えるのを、一発でやるにはどうしたらよいか?が、今回のテーマです。
方法1:置換対象が1文字の場合

最初の選択肢は「str.translate()」です。

置換対象が1文字の場合だと、見事に機能します。

例えば、半角の「A」を全角の「A」、「i」を全角の「I」、漢字の「実」を「業」に置き換えるような用途なら、以下のようにすればできます。

def trans_single(inputtext):
    encode_dic = {'A':'A','i':'I','実':'業'}
    encode_table = str.maketrans(encode_dic)
    return inputtext.translate(encode_table)
    
intext = '''東京大学大阪大学では社会人向けの「AI講座」を開いている。
また経済産業省は「AIプログラム技術」や課題解決を企業や学生らが教え合う「AI学校」を9月にも立ち上げる。
実務経験を積んだ人材が互いに鍛え合い、専門人材を育成する。
'''
print(trans_single(intext))

この結果はこんな感じ。

東京大学大阪大学では社会人向けの「AI講座」を開いている。
また経済産業省は「AIプログラム技術」や課題解決を企業や学生らが教え合う「AI学校」を9月にも立ち上げる。
務経験を積んだ人材が互いに鍛え合い、専門人材を育成する。

 きれいに辞書通りに置き換わってます。

これで辞書を以下のように単語レベルに変更してみます。

replacements = {'AI講座':'AIクラス','AIプログラム技術':'AIスキル','AI学校':'AIスクール'}

すると、こんなエラーをはいて終了してしまいます。

string keys in translate table must be of length 1

 長さが1じゃなきゃダメ・・ということです。 

方法2:単語の置き換えもできる方法

そこで「re.sub()」とlambda式の組合せでやってみます。

import re

def trans_word2(inputtext):
    replacements = {'AI講座':'AIクラス','AIプログラム技術':'AIスキル','AI学校':'AIスクール'}
    print('({})'.format('|'.join(map(re.escape, replacements.keys()))))
    return re.sub('({})'.format('|'.join(map(re.escape, replacements.keys()))), lambda m: replacements[m.group()], inputtext)
   
intext = '''東京大学大阪大学では社会人向けの「AI講座」を開いている。
また経済産業省は「AIプログラム技術」や課題解決を企業や学生らが教え合う「AI学校」を9月にも立ち上げる。
実務経験を積んだ人材が互いに鍛え合い、専門人材を育成する。
'''
print(trans_word2(intext))

これを実行すると。 

東京大学大阪大学では社会人向けの「AIクラス」を開いている。
また経済産業省は「AIスキル」や課題解決を企業や学生らが教え合う「AIスクール」を9月にも立ち上げる。
実務経験を積んだ人材が互いに鍛え合い、専門人材を育成する。

うまく意図通りの置き換えができてます。

方法2は複雑なので補足説明 

上記はうまく行くのですが、以下のように複雑な式になるので、補足しときます。

 re.sub('({})'.format('|'.join(map(re.escape, replacements.keys()))), lambda m: replacements[m.group()], inputtext)

この式の中で、

'({})'.format('|'.join(map(re.escape, replacements.keys())))

 の部分からです。

ここで辞書(例だとreplacements)を使って、正規表現の条件式を生成しています。

map関数は、「map(関数, 配列)」なので、re.escape関数で辞書のキーを処理して、エスケープ処理をさせてるだけで、その結果をjoinで連結してます。

前段の例で実行すると。

(AI\講\座|AI\プ\ロ\グ\ラ\ム\技\術|AI\学\校)

 こんな感じの条件が生成されます。

条件が括弧()でくくられているので、結果はgroup()にはいっていくわけです。

それを。

lambda m: replacements[m.group()],

で一つずつ取り出して、その結果(置換前文字列がはいっている)をキーにして、 replacementsの値(置換後文字列)をとりだして、順番にre.sub()に置き換えさせている・・というわけです。 

ではでは。