はじめに
-
当記事は下記の環境にて動作を確認しています。
- Python 3.6.2
- Python 3.6.2
-
本記事でやりたいこと
- 1つの文章中複数回出てくる単語を検出し、消したい!
例:
'サンプル:これは例文です。例えば、「これは例文です。」という表現が二回出てきているとします。'
↓
'サンプル:これは例文です。例えば、「」という表現が二回出てきているとします。'
- 1つの文章中複数回出てくる単語を検出し、消したい!
結論
下記のように正規表現を用いて置換する。({3,100}は適宜検出したい単語の長さによって変えること)
(.{3,100})(.*?)\1
↓
\1\2
2017/09/29 追記
上記の置換は単語一つ分を置換する処理なので、
置換できなくなるまでループなどで繰り返し実行すること。
scivolaさんから頂いた別解
(.{3,100})(?=.*\1)
↓
''
こちらは上記の置換と違い、ループ処理の必要がない。
ただし、"最後に残る単語"は"最も後ろの単語"となるため、下記のようになってしまう。
例:
'サンプル:これは例文です。例えば、「これは例文です。」という表現が二回出てきているとします。'
↓
'サンプル:例えば、「これは例文です。」という表現が二回出てきているとします。'
前に出てきた単語を残したい場合は、予め文字列をreverseしておき、(逆順にしておき、)
置換後に戻す、という処理が必要になる。
サンプルコード
python:test.py
# テスト用コード
import re
str = 'サンプル:これは例文です。例えば、「これは例文です。」という表現が二回出てきているとします。'
re.sub(r'(.{3,100})(.*?)\1',r'\1\2',str)
サンプルコードの実行
使用している正規表現パターンの簡単な解説
- "." : 何らかの文字(1文字)
- "*" : 直前の文字を0文字以上繰り返す
- "()" : ()内をひとまとめにする
- "\1" : ()でまとめた要素と同じものを指す。本記事中では\1なので、()でまとめられた要素のうちの一つ目を示す
- "?" : 直前の正規表現パターンを最短一致で検索する。(指定しない場合は最長一致となる)
2017/09/29 追記
いただいた別解についての解説も追加
1. "?=" : 先読み。別解においては、(.{3,100})でマッチさせる単語に対して、先読み後のパターン(.*\1)で絞込をかける
正規表現を部品ごと日本語にdecode(encode?)
- (.{3,100}) : 3~100までの文字列
- (.*?) : できるだけ短い何らかの文字列
- \1 : 1.でマッチした文字列と同じ文字列
2017/09/29 追記
いただいた別解についての解説も追加
1. (.{3,100}) : 3~100までの文字列
1. (?=.*\1) : 1. でマッチした文字列後に"何らかの文字列を挟んでもう一度同様の単語が出現しているかどうか"の絞込を追加する
注意
- (.*?)を最短一致にする意味
2017/09/29 指摘反映により内容変更
置換対象が異なります。
頭から重複している単語を調べて次に出てきた重複する単語を置換することになります。
なお、最短一致にしない場合は、一番後ろの重複する単語を置換します。(最長一致)
- {3,100}の部分は適宜検出したい単語の長さによって変えなければなりません。
'サンプル:これは例文です。例えば、「これは例文です。」という表現が二回出てきているとします。'という例においては、
'これは例文です。'は8文字なので{10,100}とすると置換できなくなります。
なお{1,100}にすると同じ文字が出た時点で置換されます。
参考URL
正規表現 HOWTO — Python 3.6.1 ドキュメント
https://docs.python.jp/3/howto/regex.html
利用可能な正規表現 - Sakura Editor
http://sakura-editor.sourceforge.net/htmlhelp/HLP000089.html