前書き
リスト内にある各文字列の開始位置と終了位置を取りたい!ってときにfindメソッドを用いたのですが、部分的に一致するものが文章の先にきてしまうと正確な位置ではない値が取れてしまいました。
そこで自分なりに改善してみた結果を以下に書いておきます。
(記事にするようなことでもないですが、アウトプットの癖をつけるためにも、自分の気づきになったことはどんなに小さなことでも残していこうかなと)
問題となった動作
例えば、以下のような文章から「カモシカ」の後に続く、「シカ」という語句の位置を取りたい場合
カモシカもシカも確かに鹿だが、アシカは確か鹿ではない
以下のようなコードを実行します。
word_list = ["カモシカ", "シカ", "アシカ"]
text = "カモシカもシカも確かに鹿だが、アシカは確か鹿ではない"
for word in word_list:
start_pos = text.find(word) # 開始位置
end_pos = text.find(word) + len(word) # 終了位置
print(word, start_pos, end_pos) # (リスト要素, 開始位置, 終了位置)
出力された結果を見ると、「シカ」の文字位置が「カモシカ」と被っていることがわかります。
カモシカ 0 4
シカ 2 4
アシカ 15 18
「シカ」の開始位置が5
、終了位置が7
というのが本来欲しい出力結果ですが、このコードでは前述した通り、そうなっていません。
解決法
スライスを利用することで、改善することができました。
以下にコードを記しておきます。
word_list = ["カモシカ", "シカ", "アシカ"]
text = "カモシカもシカも確かに鹿だが、アシカは確か鹿ではない"
#変数を用意して繰り返しの都度、検索する範囲を変更する
next_search_spos = 0
for word in word_list:
start_pos = len(text[:next_search_spos]) + text[next_search_spos:].find(word) # 開始位置
end_pos = len(text[:next_search_spos]) + text[next_search_spos:].find(word) + len(word) # 終了位置
print(word, start_pos, end_pos) # (リスト要素, 開始位置, 終了位置)
next_search_spos = end_pos
変数を用意して初期値を0に設定し、その後はfor文の最後にそのループ回の語句の終了位置を代入する一文を挟むことで、文字位置の被りを避けることができました。
カモシカ 0 4
シカ 5 7
アシカ 15 18
終わりに
今回のやり方が最善なのか、少し不安ながらも存外早くに解決できてよかったです。
研究活動でPythonを使ってはいるものの、プログラムをいじることが少ないのでまだまだ勉強が足りていないと痛感しています。
これからも頑張る:D
追記(2023/05/15) コードに関する注意
この記事に書いたコードではその仕様上、リスト内の要素の順序が文中における出現順でなければならず、仮に「シカ」のみを対象に位置を取りたい場合は正確な出力が得られないことに気づきました。
word_list = ["アシカ", "カモシカ", "シカ"]
word_list = ["シカ"]
上記に挙げたような形態では出力が正確ではなくなります。<_(._.)_>
コメントでご指摘下さりありがとうございます。
精進します!