背景
spaCyは自然言語処理ライブラリとして使用でき、単語単位で分解して、品詞などで
分類することができます。また、mathcerを使用して、品詞や正規表現、数字、文字列の形式などで
マッチした部分を抜き出して処理したりすることができます。
今回は、spaCyでIPアドレスを一致した個所を置換する方法を記述します。
環境準備
以下のpython3とpipが使用できるようにしておくことが前提です。
言語: python3
以下のライブラリをインストールします。
ライブラリ: spaCy,ja_ginza(統計モデル)
pip install -U ja_ginza,ginza,spacy
実装
import spacy
from spacy.matcher import Matcher
def ipreplace():
# ja_ginzaモデルをロードして、モデル内のvocabオブジェクト(言語素やstrigstore)を基にマッチルールを作成します。
nlp = spacy.load("ja_ginza")
matcher = Matcher(nlp.vocab)
message = "このIPアドレスは 192.168.3.2 と 10.3.3.4 が割り振られています。"
# nlpで処理結果を保持する中核のオブジェクトを作成。docオブジェクトが生成されます。
doc = nlp(message)
# ここでは、「d,dd,dddのいずれかの形に数字が一致+.」を繰り返したパターンを作成します。
# 例えば、1,12,123のような形のいずれか
pattern = [
{"SHAPE":{"IN":["d","dd","ddd"]}},
{"TEXT":"."},
{"SHAPE":{"IN":["d","dd","ddd"]}},
{"TEXT":"."},
{"SHAPE":{"IN":["d","dd","ddd"]}},
{"TEXT":"."},
{"SHAPE":{"IN":["d","dd","ddd"]}}
]
# 作成したパターンと一致したときのインデックスをmatcherに追加します。
matcher.add("IPADDRESS",[pattern])
# docオブジェクトのうち、patternに一致した文字列の開始、終了位置、インデックスを
# 一致した単語部分をリスト型として取得します。
matches = matcher(doc)
newMessage = message
# 一致した情報(開始位置、終了位置、インデックス)がmatches[]に追加されているので、
# for分で取り出す。
for match_id,start,end in matches:
#docオブジェクトは開始、終了位置でsliceオブジェクトとして取り出せる。
matchWord = str(doc[start:end])
#テキストを一致した単語と置換する。
newMessage = newMessage.replace(matchWord,"***.***.***.***")
print(newMessage)
if __name__ == "__main__":
ipreplace()
実行結果
>>> ipreplace.py
このIPアドレスは ***.***.***.*** と ***.***.***.*** が割り振られています。
ちょっと解説
コード内のコメントのほとんど書いているので補足程度
patternですが、dは数字を表します。
以下は、d,dd,dddの形のうち一つを含む形があることを示します。
なので、1,12,123のような数字の組み合わせのうち一つを検出します。
{"SHAPE":{"IN":["d","dd","ddd"]}
以下はIPアドレスの.(コンマ)を検出します。
{"TEXT":"."}
なので、この組み合わせを使用して、XXX.XXX.XXX.XXXやXX.X.XXX.XXなどの組み合わせを
検出するパターンを作成できます。
matcherに、docオブジェクトを渡し、patternに一致した
docオブジェクトの配列の位置とmatcher.addで設定したインデックスIDをmatchesに代入します。
matches = matcher(doc)
newMessage = message
for分でmatches内のオブジェクトを取り出して、docをstart位置、end位置でdocから切り抜きます。
切り抜いた単語を元のテキストより、置換します。
for match_id,start,end in matches:
matchWord = str(doc[start:end])
newMessage = newMessage.replace(matchWord,"***.***.***.***")
これで、置換が完了するので、置換後のテキストnewMessageを返すか、表示させるなどして使用します。
補足
match_idは、nlp.vocab.strings[match_id]で、mathcer.addで設定したインデックス名に変換できます。
for match_id,start,end in matches:
print(nlp.vocab.strings[match_id])
表示結果
>>> IPADDRESS
>>> IPADDRESS
patternをいくつも作り、mathcer.addを複数化実施する際に、それぞれのmathcer.addにインデックスを別にして、
if分などで条件分岐をさせると、マッチした内容で処理を変えることができます。
参考URL