Skip to content

Instantly share code, notes, and snippets.

@pekeq
Created November 14, 2017 23:01
Show Gist options
  • Save pekeq/9c0fc099f4203a4299289db29507cad7 to your computer and use it in GitHub Desktop.
Save pekeq/9c0fc099f4203a4299289db29507cad7 to your computer and use it in GitHub Desktop.
オレオレ正規化処理 (Python3)
# coding: utf8
# オレオレ正規化処理 (Python3)
# 正規表現コンパイルをメソッドの外に書いたのでそこそこ速い
import re
import unicodedata
# inspired from https://github.com/neologd/mecab-ipadic-neologd/wiki/Regexp.ja
# 以下を参考させていただきました
# http://d.hatena.ne.jp/s_hiiragi/20110111/1294755929
# https://hydrocul.github.io/wiki/blog/2014/1101-hyphen-minus-wave-tilde.html
# https://github.com/ikegami-yukino/neologdn
# https://ja.wikipedia.org/wiki/%E3%83%8F%E3%82%A4%E3%83%95%E3%83%B3
# https://ja.wikipedia.org/wiki/%E6%B3%A2%E3%83%80%E3%83%83%E3%82%B7%E3%83%A5
# 幅のない空白
# - 右から書く言語で使うU+200E, U+200FはSPACEではないが、ここに入れる
# - soft hyphen U+00AD もここに入れる
re_ZERO_WIDTH_SPACES = re.compile(r'[\u200B\u200C\u200D\u200E\u200F\uFEFF\u00AD]')
# 各種空白文字
re_SPACES = re.compile(r'[ \t\u2028\u2029\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000]+')
# ハイフンに統一するもの
re_HYPHENS = re.compile(r'[\u2010\u002D\u2011\u2043\u2212]+')
# wavedashに統一するもの
re_WAVEDASHES = re.compile(r'[\u301C\u02DC\u1FC0\u2053\u223C\u223F\u3030\uFF5E]+')
# 長音
re_CHOONPUS = re.compile(r'\u30FC+')
# 実体参照
re_AMP = re.compile(r'&')
re_QUOT = re.compile(r'"')
re_LT = re.compile(r'<')
re_GT = re.compile(r'>')
# 全角ダブルクォートを半角に
REPLACE_QUOTES = str.maketrans('”“’‘', '""\'\'')
# 軽い(?)正規化処理
# 表記のゆれを整える程度
def normalize(s):
# 幅のない空白は削除
s = re_ZERO_WIDTH_SPACES.sub('', s)
# 一部の実体参照を展開
s = re_AMP.sub('&', s)
s = re_QUOT.sub("'", s)
s = re_LT.sub('<', s)
s = re_GT.sub('>', s)
# 全角ダブルクォートを半角に
s = s.translate(REPLACE_QUOTES)
# unicode正規化
s = unicodedata.normalize('NFKC', s)
# ハイフンゆれ
s = re_HYPHENS.sub('-', s)
# wavedashゆれ
s = re_WAVEDASHES.sub('\u301C', s)
# 長音まとめる
s = re_CHOONPUS.sub('\u30FC', s)
# 空白文字まとめる
s = re_SPACES.sub(' ', s)
return s.strip()
# カット対象
# - 変換されなかった実体参照
re_TO_STRIP = re.compile(r'&[#\w\d]+;')
# カット対象(空白に変換)
# - wikipediaの図表,code引用
re_TO_SPACE = re.compile(r'(formula|codice)_\d+')
# 数字
re_NUMBERS = re.compile(r'\d+')
# ローマ数字は全部 0 に変換
REPLACE_ROMANS = str.maketrans('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ', '0000000000')
# word2vecする前の正規化処理
def full_normalize(s):
# ローマ数字
s = s.translate(REPLACE_ROMANS)
# スペースに変換
s = re_TO_SPACE.sub(' ', s)
s = normalize(s)
# 不要部分削除
s = re_TO_STRIP.sub('', s)
# 英文字は小文字に
s = s.lower()
# 数字は0に変換。連続していたらまとめる
s = re_NUMBERS.sub('0', s)
return s
if __name__ == "__main__":
assert '' == normalize('\u200B\u200C\u200D\u200E\u200F\uFEFF')
assert 'ルパンIII世' == normalize('ルパンⅢ世')
assert 'ルパン0世' == full_normalize('ルパンⅢ世')
assert 'copy&right' == full_normalize('copy&amp;right&copy;')
assert 'g0カービン' == full_normalize('G13カービン')
assert '空 白 空 白' == normalize('空 白 空 白')
assert "お\"お\"" == normalize("お“お”")
assert "ハンカク" == normalize("ハンカク")
assert "0" == full_normalize("0123456789")
assert "abcdefghijklmnopqrstuvwxyz" == full_normalize("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
assert "abcdefghijklmnopqrstuvwxyz" == normalize("abcdefghijklmnopqrstuvwxyz")
assert "!\"#$%&'()*+,-./:;<>?@[¥]^_`{|}" == normalize("!”#$%&’()*+,-./:;<>?@[¥]^_`{|}")
assert "=。、・「」" == normalize("=。、・「」")
assert "ハンカク" == normalize("ハンカク")
assert "o-o" == normalize("o₋o")
#assert "majikaー" == normalize("majika━")
assert "わ〜い" == normalize("わ〰い")
assert "スーパー" == normalize("スーパーーーー")
assert "!#" == normalize("!#")
assert "ゼンカク スペース" == normalize("ゼンカク スペース")
assert "お お" == normalize("お お")
assert "おお" == normalize(" おお")
assert "おお" == normalize("おお ")
assert "-" == normalize('---------------')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment