Pythonで文字列置換された場所を簡単に発見するには?(コードつき)
文字列を扱うシステム開発してると、文字列の差分表示をしたくなります。
さらには、差分があるところになんか処理したくなることもよくよくあります。
この記事で書くこと
スペースが改行に置換されたところを知りたい。言い換えると、テキストアライメントを取得したい。
この記事の前提
- ある作業で少し困ったファイルに出会った。
- システム都合で、改行が自動的にスペースに変換されている。
- 自然言語処理的に改行は大切なことがあるので、スペースから改行に復元したい。
- システム処理前のテキスト処理前(改行あり)とシステム処理後のテキスト(スペース置換)の両方が手元にある。
- 復元規則を発見するために、システム処理前と処理後の比較をしたい。
こんな風に実現する
Pythonの標準パッケージでdifflibというのがある。
difflibの中にget_opcodes()というメソッドがあって、これが文字列の置換情報を表示してくれる。
まずはテスト的に使ってみる。確かにスペースが改行になったところが文字インデックスで取得できている。
1 2 3 4 5 6 7 8 9 10 11 12 |
import difflib a = 'これは\nいいですね\n' b = 'これは いいですね' s_obj = difflib.SequenceMatcher(None, a, b) s_obj.get_opcodes() >> [('equal', 0, 3, 0, 3), ('replace', 3, 4, 3, 4), ('equal', 4, 9, 4, 9), ('delete', 9, 10, 9, 9)] b[3:4] >> ' ' b[3:4], a[3:4] >> (' ', '\n') b[9:9], a[9:10] >> ('', '\n') |
作った関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
def detect_string_diff(text_dump: str, text_original: str) -> List[Tuple[str, str]]: # dumpテキストですべてのスペース位置を探索しておく seq_space_index = sorted([m_obj.regs[0] for m_obj in re.finditer(' ', text_dump)], key=lambda t: t[0]) # dumpがoriginalに復元される過程を探索する s_obj = difflib.SequenceMatcher(None, text_dump, text_original) # 変更処理のうち、スペースに関する'replace'と文末の'insert'だけを取得する。 # スペース変換は変換後が改行である場合のみを取得する。 seq_space_modification = {(mod_tuple[1], mod_tuple[2]): mod_tuple for mod_tuple in s_obj.get_opcodes() if mod_tuple[0] in ['replace'] and (text_dump[mod_tuple[1]:mod_tuple[2]] == ' ' and text_original[mod_tuple[3]:mod_tuple[4]] == '\n')} # 変更箇所を保存しておくリスト __stack = [] # 直前のスペース区間が終了しているインデックス __end_last_space_index = 0 for space_index in seq_space_index: # スペースが含まれる区間を切り出す __text_with_text = text_dump[__end_last_space_index:space_index[1]] # スペース区間 = 置換区間?を確認する if space_index in seq_space_modification: # スペース置換がされている箇所である。なので、ラベル1をたてる __stack.append((text_dump=__text_with_text, label=1)) else: # スペース置換はされていないので、negative sample 0ラベル __stack.append((text_dump=__text_with_text, label=0)) # __end_last_space_indexを更新しておく __end_last_space_index = space_index[1] else: pass return __stack |
1 |
おしまい! |
ディスカッション
コメント一覧
まだ、コメントがありません