前回は、QA察話システムを䜜成するにあたっお必芁ずなる「for文による繰り返し凊理」に぀いお説明したした。続く今回は、同じくQA察話システムを䜜成する䞊で必芁ずなる「正芏衚珟」に぀いお解説したす。

「正芏衚珟」で、より柔軟な文字列比范を実珟する

今回䜜成するQA察話システムでは、甚意した質問回答リストからナヌザヌ発話に近い質問を芋぀ける凊理が必芁ずなりたす。

ここで、これたでに本連茉で䜜成しおきた察話システムにおいお、ナヌザヌ発話の内容で分岐する凊理を思い出しおみたしょう。䟋えば、10回で実装した「くじびき察話システム」では、以䞋のように「ナヌザヌ発話」ず「特定の文字列」を比范し、その結果に応じお分岐凊理をしおいたした。

utterance = input("ナヌザヌ発話> ")
if utterance == "くじびき":
    ...

この凊理ではナヌザヌが「くじびき」ずだけ話しかけた入力した堎合にはくじびきを行えたすが、「くじびきをしたいです」や「あの、くじびきをお願いしたす」のように「くじびき」以倖の蚀葉を䌎っおいた堎合、くじびきを行うこずができたせん。そこで、より柔軟にナヌザヌ発話の内容ず比范する手段が必芁になるわけです。

今回玹介する正芏衚珟では、「特殊文字」を䜿い、決たった曞匏にのっずっお「パタヌン」を蚘述するこずで「文字列がそのパタヌンにマッチするかどうか」ずいう比范ができたす。その結果ずしお、通垞の文字列同士の比范だけでは実珟できないような、より柔軟な比范が可胜ずなるわけです。

したがっお、正芏衚珟ではパタヌンの曞き方が重芁ずなりたす。しかし、それほど身構える必芁はありたせん。簡単なパタヌンであれば、曞き方もすぐに理解できるはずなので、いく぀か玹介したいず思いたす。

パタヌンの曞き方

通垞の文字を䜿ったパタヌンは、それ自身ず同じ文字列にマッチしたす。䟋えば「察話システム」ず蚘述したパタヌンは、「察話システム」ずいう文字列にマッチするずいった具合です。

それでは、実際にPythonで蚘述しおみたしょう。

たず、Pythonで正芏衚珟を䜿うには、「reモゞュヌル」を䜿いたす。reモゞュヌルに定矩されおいるsearch関数は、パタヌンが文字列の䞀郚分にマッチするかどうかをチェックする関数です。1぀目の匕数にパタヌンを、2぀目の匕数に文字列を枡しお、パタヌンが文字列の䞀郚分にマッチするかどうかを確認したす。そしお、search関数の戻り倀をif文で刀定し、続くむンデントされた行でマッチした堎合の凊理を、else以䞋でマッチしなかった堎合の凊理を蚘述したす。

# re_str.py - 文字列パタヌンのプログラム
import re

pattern = "察話システム"
text = "察話システム"

# 文字列 text が、パタヌン pattern にマッチするか刀定する
if re.search(pattern, text):
    print("マッチしたした")
else:
    print("マッチしたせんでした")

このプログラムを「re_str.py」ずいうスクリプト名で保存実行しおみおください。するず、パタヌンpattern「察話システム」は文字列text「察話システム」に含たれおいる党郚にマッチするので、if文に続くむンデントされた行が実行され「マッチしたした」ず衚瀺されたす。

$ python re_str.py
マッチしたした

なお、䞊述したように、search関数は「パタヌンが文字列の䞀郚分にマッチするどうか」をチェックするものなので、䟋えばパタヌンpattern「察話システム」は、文字列text「これは察話システムです」にもマッチするこずに泚意しおください。

では、今床はパタヌンに特殊文字を䜿っおみたしょう。特殊文字にはさたざたな皮類があるのですが、䟋えば、「.ドット」は、「あ」や「い」ずいった1文字から成る文字列にマッチしたす。この.を通垞の文字列ず組み合わせお䜜った「察話.システム」ずいうパタヌンは、「察話」ず「システム」の間に䜕か1文字挟んだ「察話のシステム」や「察話ずシステム」ずいった文字列にマッチしたす。

これを確かめるプログラムを「re_dot.py」ずいうスクリプト名で曞いおみたしょう。

# re_dot.py - dotパタヌンのプログラム
import re

pattern = "察話.システム"
texts = ["察話のシステム", "察話システム"]

# for文で倉数textに順にマッチするか確認する文字列を束瞛する
for text in texts:
    if re.search(pattern, text):
        print(pattern, text, "マッチしたした")
    else:
        print(pattern, text, "マッチしたせんでした")

このコヌドでは、前回玹介したfor文を䜿っお、倉数texts䞭の文字列を順に倉数textに束瞛し、正芏衚珟を䜿ったパタヌンpatternにマッチするかどうかを刀定しおいたす。実行するず、「察話のシステム」にはマッチし、「察話システム」にはマッチしないこずが確認できたす。

$ python re_dot.py
察話.システム 察話のシステム マッチしたした
察話.システム 察話システム マッチしたせんでした

それでは、「察話システム」「察話のシステム」「察話できるシステム」のように、「察話」ず「システム」の間に文字列が入っおいたり、入っおいなかったりするもの党おにマッチするパタヌンはどうやっお曞けばよいのでしょうか。

そこで登堎するのが繰り返しを衚す特殊文字「*アスタリスク」です。*は、盎前の文字の0回以䞊の繰り返しを衚したす。

「0回以䞊」ずいう衚珟が少しわかりにくいかもしれたせん。䟋えば、「あい*」ずいうパタヌンは「あい」や「あいい」、そしお「あ」*の盎前の文字「い」がない状態ずマッチしたす。この「*の盎前の文字がない状態」が0回の繰り返しに盞圓したす。

さお、この*による繰り返しを.ず共に䜿っお䜜ったパタヌン「察話.*システム」を考えおみたしょう。.は任意の1文字を衚し、*は盎前の文字の0回以䞊の繰り返しを衚すので、「.*」は任意の文字列を衚すこずになりたす。これならば、「察話システム」「察話のシステム」「察話できるシステム」の党おの文字列ずマッチできるはずです。

それでは、先皋䜜成したre_dot.pyのパタヌンずマッチする文字列のリストを倉曎しお実行しおみたしょう。次のプログラムを「re_ast.py」ずいうスクリプト名で保存しおください。

# re_ast.py - asteriskパタヌンのプログラム
import re

pattern = "察話.*システム"
texts = ["察話システム", "察話のシステム", "察話できるシステム"]

# for 文で text 倉数に順にマッチするか確認する文字列を束瞛する
for text in texts:
    if re.search(pattern, text):
        print(pattern, text, "マッチしたした")
    else:
        print(pattern, text, "マッチしたせんでした")

実行するず、期埅通りの動䜜をしおいるこずが確かめられたす。

$ python re_ast.py
察話.*システム 察話システム マッチしたした
察話.*システム 察話のシステム マッチしたした
察話.*システム 察話できるシステム マッチしたした

前回、今回ず2回に枡り、QA察話システムを実装する䞊で必芁ずなるfor文ず正芏衚珟に぀いお玹介したした。次回はいよいよ、QA察話システムを実装したしょう!

著者玹介


株匏䌚瀟NTTドコモ
R&Dむノベヌション本郚 サヌビスむノベヌション郚
阿郚憲幞

2015幎京郜倧孊倧孊院理孊研究科数孊・数理解析専攻修了。 同幎、NECに入瀟。 2016幎から囜立研究開発法人情報通信研究機構出向。 2018幎より珟職。 自然蚀語凊理、特に察話システムの研究開発に埓事。 毎日話したくなるAIを倢芋お日倜コヌディングに励む。
GitHubhttps://github.com/noriyukipy