K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

ルビ付きテキストから読み仮名を抽出・除去する

01.7.9

ルビ付きテキストから読み仮名を抽出・除去する

最終更新 2020-05-20 読了時間 2 分
まとめ
ニュース記事や議事録の「機械学習(きかいがくしゅう)」のような括弧ルビと、Web ページの <ruby>教師あり学習<rt>きょうしあり</rt></ruby> のような HTML ルビを、1 つの関数で本文から取り除き、同時に (漢字, 読み) のペアとして別リストに保存します。仕組みは正規表現 re.sub にコールバック関数を渡し、一致するたびに読みを readings へ追記してから漢字だけを返す、というものです。読み仮名は検索用の別カラムに、ルビを除いた本文は形態素解析に渡す、という 2 つの用途を 1 回の走査で満たします。

直感 #

「機械学習(きかいがくしゅう)を支える」をそのまま形態素解析器に入れると、「(」「きかいがくしゅう」「)」が独立したトークンになり、単語の頻度も文の長さも歪みます。ルビは本文ではなく「漢字に付いた注釈」です。だから本文からは外し、別の場所に「機械学習 → きかいがくしゅう」という対応だけ残しておけば、検索では読みで引けて、解析では本文だけを使えます。括弧ルビは「漢字の連続の直後に全角括弧で囲まれた仮名」というパターンで、HTML ルビは <ruby> と <rt> のタグで囲まれているので、どちらも正規表現 1 本ずつで見つけられます。

Python で抽出する #

次のコードは括弧ルビと HTML ルビの 2 つの正規表現を定義し、extract_ruby がルビを除いた本文と (漢字, 読み) のリストを返します。サンプルは 1 文の中に両方の形式を含んでいます。

 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
import re

PAREN_RUBY = re.compile(r"([一-龥々〆ヵヶ]+)(([ぁ-んァ-ン]+))")
HTML_RUBY = re.compile(r"<ruby>(.+?)<rt>(.+?)</rt></ruby>")

def extract_ruby(text: str) -> tuple[str, list[tuple[str, str]]]:
    readings: list[tuple[str, str]] = []

    def replace_paren(match: re.Match[str]) -> str:
        kanji, ruby = match.groups()
        readings.append((kanji, ruby))
        return kanji

    text = PAREN_RUBY.sub(replace_paren, text)

    def replace_html(match: re.Match[str]) -> str:
        kanji, ruby = match.groups()
        readings.append((kanji, ruby))
        return kanji

    text = HTML_RUBY.sub(replace_html, text)
    return text, readings

sample = "機械学習(きかいがくしゅう)を支える<ruby>教師あり学習<rt>きょうしあり</rt></ruby>の基礎"
cleaned, ruby_list = extract_ruby(sample)
print(cleaned)
print(ruby_list)

実行結果の読み方 #

cleaned は「機械学習を支える教師あり学習の基礎」で、形態素解析に渡してもルビの括弧やタグがトークンに混ざりません。ruby_list は 2 要素のリストで、1 つ目が括弧ルビ、2 つ目が HTML ルビから取れた (漢字, 読み) のペアです。括弧ルビの読みに長音「ー」が含まれる「珈琲(コーヒー)」のようなケースは一致しないので、対象データにカタカナ読みが多いなら PAREN_RUBY の文字クラスに ー を足してください。

使いどころと落とし穴 #

読み仮名を別フィールドに分離したうえで、検索時には漢字・かな・ローマ字のすべてから引ける逆引き辞書({"きかいがくしゅう": "機械学習"})を作ると、ユーザーが読みしか知らない語でも検索でヒットします。電子書籍の EPUB では <rb> <rt> <rp> の組み合わせが使われるため、HTML_RUBY ではなく BeautifulSoup でタグを抽出します。応用として、文書全体に対する len(ruby_list) と文字数の比率を「ルビ密度」として算出し、密度が高いページを優先的にやさしい日本語版や翻訳の対象にする、といったワークフローにも使えます。