動機
踊り字とは, "いらいら"を"いら/\"のように, 繰り返しを省略するものですが, 中には"それ/″\ -> それぞれ"のように, 濁音を付与するものもあります.
自然言語処理の前処理でこれらをどうにかしようと思って調べてみたら, 案外これについての記事がなかったので書きました.
コード
Pythonで書きます
def dakuon_for_char(c: str) -> str:
# 一文字だけ濁音に直す
if ord('か') <= ord(c) <= ord('ち') and ord(c) % 2 == ord('か') % 2:
return chr(ord(c) + 1)
if ord('つ') <= ord(c) <= ord('と') and ord(c) % 2 == ord('つ') % 2:
return chr(ord(c) + 1)
if ord('は') <= ord(c) <= ord('ほ') and ord(c) % 3 == ord('は') % 3:
return chr(ord(c) + 1)
if ord("カ") <= ord(c) <= ord("チ") and ord(c) % 2 == ord("カ") % 2:
return chr(ord(c) + 1)
if ord("ツ") <= ord(c) <= ord("ト") and ord(c) % 2 == ord("ツ") % 2:
return chr(ord(c) + 1)
if ord("ハ") <= ord(c) <= ord("ホ") and ord(c) % 3 == ord("ハ") % 3:
return chr(ord(c) + 1)
if (c == "う"):
return "\u3094"
if (c == "ウ"):
return "\u30F4"
return c
def dakuon(s: str) -> str:
return "".join(map(dakuon_for_char, s))
テスト
print(dakuon("あいうえお")) # あいゔえお
print(dakuon("かきくけこ")) # がぎぐげご
print(dakuon("さしすせそ")) # ざじずぜぞ
print(dakuon("たちつてと")) # だぢづでど
print(dakuon("なにぬねの")) # なにぬねの
print(dakuon("はひふへほ")) # ばびぶべぼ
print(dakuon("アイウエオ")) # アイヴエオ
print(dakuon("カキクケコ")) # ガギグゲゴ
print(dakuon("サシスセソ")) # ザジズゼゾ
print(dakuon("タチツテト")) # ダヂヅデド
print(dakuon("ナニヌネノ")) # ナニヌネノ
print(dakuon("ハヒフヘホ")) # バビブベボ
解説
ordはunicodeコードポイントを取ってくる関数で
chrはそれを文字列に戻す関数です.
以下, う以外について
Unicode一覧を眺めてみると, 文字コードについて, 濁音は常に清音より1だけ大きいことが分かります.
"か"から"ち"までは連続しているので, ここの範囲に属する文字は偶奇が"か"と一致すれば清音と
促音の"っ"でずれているので上と別処理になってしまいますが, "つてと"も同じ考え方で処理できます.
は行は半濁音が入ってきて, "は"と"ひ"のようにとなり合わせの清音は3だけずれるので, ここは3で割った剰余で判定します.
最後に"う"と"ウ"だけは別処理にしていますが, これらについては別に濁音にしたくないときのほうが多いと思うので, 必要に応じて消してください.
以下20240306追記
青空文庫の踊り字を解決する
青空文庫作業マニュアルによれば, 踊り字は"/\"となっていますが, 実際のテキストを確認したところ"/\"となっているものもあったので, 念のため両方に対応します.
上で紹介したdakuon関数をどっかに入れてください.
import re
def preprocess(text):
text = re.sub(r"(?P<mae>..)[/|/]\", r"\g<mae>\g<mae>", text)
f = lambda s: s.group("mae") + dakuon(s.group("mae")[0]) + s.group("mae")[1]
text = re.sub(r'(?P<mae>..)[/|/]″\', f, text) # ″は全角文字であることに注意
return text
text = "ニャー、ニャーと試みにやつて見たが誰も來ない。其内池の上をさら/\と風が渡つて日が暮れかゝる。"
print(preprocess(text))
# ニャー、ニャーと試みにやつて見たが誰も來ない。其内池の上をさらさらと風が渡つて日が暮れかゝる。
text = "其時におさんと云ふ者はつく/″\いやになつた"
print(preprocess(text))
# 其時におさんと云ふ者はつくづくいやになつた
ただし, これでは対策できない例外もあります.
吾輩は猫であるを見ていただくと, 「ニャー/\泣いて居た」という文章が出てきます. これを上の関数を用いて処理すると「ニャーャー泣いて居た」になってしまうでしょう.
対策として考えられるのは, "ニャ"のような, 小文字付きのものを一文字として見るように, (?P<mae>..)の部分を工夫することです.