米国の発音辞書は、猫(cat)は K AE1 T のように聞こえると言います。国際音声記号(IPA)は同じ音を kæt と書きます。別の ASCII 専用の体系はこれを k"{t と書きます。三つとも、まったく同じ二つの音素 — “k” の音の後に短い “a”、そして “t” — を記述しています。音について何も変わっていません。それを書き記すのに使われたアルファベットが変わっただけです。
これは、複数の出典から発音データを組み合わせる誰にとっても常に起こることです。米国の辞書から作られた音声データセットは一つの表記法を使います。ヨーロッパの辞書は別のものを使います。テキスト音声変換エンジンは三つ目のものを期待します。そのデータを統合したり、検索したり、比較したりする前に、それを一つの音声アルファベットから別のものへ翻訳しなければなりません — 人間の言語間で翻訳者が行うのと同じ仕事ですが、ここでの「言語」は単語を書く方法ではなく音を書く方法です。
scriptconv はこの翻訳を行う小さな Python ライブラリで、加えて一段階上の関連する仕事も行います。他の何かをする前に、テキストの断片がそもそもどの文字体系であるかを見極めることです。これは言語学に関する意見を持ちません — 単語がどう発音されるかを推測することはありません。すでに既知の音を表している記号を、ある表記法から別の表記法へ移動させるだけで、文字自体から文字体系を識別するだけです。
いくつかの用語を明確に定義する
- 文字体系(Script): ラテン文字、キリル文字、ハングルのような、実際の文字集合である書記体系。言語とは同じではありません。英語、フランス語、ベトナム語はすべてラテン文字を使い、セルビア語はキリル文字またはラテン文字のどちらでも書けます。
- 正書法(Orthography): ある特定の言語をある文字体系で書くための慣習的な綴りの規則 — 大文字小文字、アクセント記号、分かち書き。
- 音素(Phoneme): ある言語における区別される音の単位、例えば “cat” の “k” の音。
- IPA(国際音声記号): ある言語の通常の綴りとは独立して、音を正確に書き表すための標準的なアルファベット。
- 音訳(Transliteration): 発音ではなく元の綴りを正確に保存することを目指して、文字をマッピングすることでテキストをある文字体系から別の文字体系に変換すること。
- ローマ字化(Romanization): 特にラテン文字への音訳。
なぜ ASCII 専用の音声アルファベットがそもそも存在するのか
IPA は、標準的なキーボードにはない ʃ、ʒ、ə、ˈ のような文字を必要とします。それは、Unicode が普遍的になり、ほとんどのフォント、端末、ファイル形式が非 ASCII テキストを確実にサポートするようになる以前の、数十年にわたるコンピューティングにおける実際の問題でした。研究者たちは ASCII 専用の代替物を作りました。アメリカ英語の音声認識研究のために開発された ARPABET と、メールや古い端末でも安全なように開発された、完全な IPA の ASCII エンコーディングである X-SAMPA です。これらは歴史的な珍品ではありません。ARPABET は今でも広く展開されている米国英語の発音辞書と音声ツールが使う表記法であり、X-SAMPA は今でも平文が必要な言語学ツールに現れます。そのデータを読むものは何でも、その アルファベットを読める必要があります。
scriptconv は実際の変換を行います。これは説明ではなく、実行された出力です。
from scriptconv import convert, arpa_to_ipa, ipa_to_arpa
convert("K AE1 T", "arpa", "ipa")
# 'kæt'
convert("HH AH0 L OW1", "arpa", "ipa")
# 'həloʊ'
convert("kˈæt", "ipa", "x-sampa")
# 'k"{t'
arpa_to_ipa("HH AH0 L OW1", stress=True)
# 'həlˈoʊ'
ipa_to_arpa("həlˈoʊ", stress=True)
# 'HH AH0 L OW1'
強勢の記号は往復変換を生き残ります。ARPABET は母音に付けた数字で強勢を示し(OW1)、IPA は強勢のある音節の前に ˈ を置いて示します。arpa_to_ipa(..., stress=True) はその情報を向こう側に運び、戻す変換は元の数字を正確に再構築します。
IPA は設計上、このすべての中心に位置しています。scriptconv はすべての表記法をグラフのノードとして、すべての変換器を辺として扱い、表記法のペアごとに直接変換器を手書きする代わりに IPA をハブとして変換を経路づけます。
from scriptconv import DEFAULT_GRAPH
[f"{e.src}->{e.dst}" for e in DEFAULT_GRAPH.route("arpa", "x-sampa")]
# ['arpa->ipa', 'ipa->x-sampa']
このハブを通じて、合計九つの表記法がトランスコードされます。ARPABET、X-SAMPA、Kirshenbaum、Lexique、Cotovía、RFE、mantoq、そして以下で扱う Buckwalter です。
他の何かをする前に文字体系を検出する
ソフトウェアがテキストの断片をどう処理するか — どちらの向きにレンダリングするか、どのスペルチェッカーを実行するか、どのフォントを選ぶか — を決める前に、そのテキストがどの文字体系であるかを知る必要があります。これはそれがどの言語であるかとは異なる問いです。文字体系は文字集合を識別し、言語は語彙と文法を識別します。繰り返しになりますが、セルビア語はキリル文字にもラテン文字にもなり得ます。ウズベク語もそうです。scriptconv は文字そのものから直接文字体系を検出し、別途、言語コードをそれが慣習的に書かれる文字体系にマッピングします。
from scriptconv import detect_script, script_runs, lang_to_script, base_direction
detect_script("Здравствуйте")
# 'Cyrl'
detect_script("안녕하세요")
# 'Hang'
script_runs("привет hello")
# [('Cyrl', 'привет '), ('Latn', 'hello')]
base_direction("مرحبا hello")
# 'mixed'
lang_to_script("uzb_cyr")
# 'Cyrl'
detect_script は ISO 15924 コード — 文字体系のための標準的な四文字タグレジストリ(キリル文字は Cyrl、ハングルは Hang、ラテン文字は Latn、アラビア文字は Arab) — を返します。script_runs は混在したテキストを文字体系ごとの連続した区間に分割します。これは、レンダラーが文単位でどのフォントとテキスト方向を適用するかを決めるために必要なものです。base_direction は、混在した文字列が左から右に、右から左に、あるいは両方向に読まれるかを報告します。
難しいケース: Buckwalter、ハングル、かな
三つの文字体系の変換は、実際のパイプラインで十分頻繁に登場するため、scriptconv はそれぞれを直接扱います。
アラビア語のための Buckwalter は、すべてのアラビア文字と分音記号を特定の ASCII 文字に一対一でマッピングする ASCII 音訳方式であり、元の綴り — ほとんどのネイティブテキストが省略する母音記号を含めて — を正確に再構築できるようにします。これは、アラビア文字が ASCII を中心に構築されたパイプラインやツールで扱いにくいために存在します。マッピングが正確で可逆的でありさえすれば、並べ替え、差分の確認、正規表現、古いテキスト形式はすべて、テキストがラテン文字の ASCII になった瞬間に簡単になります。
from scriptconv import buckwalter_to_arabic, arabic_to_buckwalter
buckwalter_to_arabic("mrHbA")
# 'مرحبا'
arabic_to_buckwalter("مرحبا")
# 'mrHbA'
arabic_to_buckwalter("رحمٰن")
# 'rHm`n'
最後の例には、少数の単語(رحمٰن、rahman)で使われる小さな上付きの分音記号であるダガーアリフが含まれています — Buckwalter は通常のアリフとは区別される特定の ASCII 文字(`)をこれのために予約しているため、音訳が両者を潰してしまうことはありません。
ハングル は音節ブロックのように見えますが、各ブロックは格子状に配置された個々の文字(字母)の合成クラスターです — “H”、“A”、“N” が左から右に書かれる代わりに視覚的に組み合わさって “han” という一つのグリフになるのと同じようなものです。検索のためであれ、音韻論的分析のためであれ、別のシステムに供給するためであれ、個々の文字を必要とするソフトウェアは、それらを再び分離しなければなりません。
from scriptconv.translit import decompose_hangul
decompose_hangul("한국")
# 'ㅎㅏㄴㄱㅜㄱ'
decompose_hangul("국민")
# 'ㄱㅜㄱㅁㅣㄴ'
最後の例は、それがしないことによって重要です。국민(gungmin、「国民」)は鼻音化同化を経て [ɡuŋmin] と発音されますが、decompose_hangul は分解が音韻規則ではなく Unicode コードポイントに対する算術であるため、同化されていないまま書かれたとおりの文字 — ㄱㅜㄱㅁㅣㄴ — を返します。これは何が書かれたかを教えるのであって、どう聞こえるかを教えるものではありません。
かな の変換は、日本語の二つの音節文字体系であるひらがなとカタカナの間を行き来し、これらは固定されたコードポイントのオフセットで同じ音を異なる文字で表します。
from scriptconv import hira_to_kana, kana_to_hira
hira_to_kana("こんにちは")
# 'コンニチハ'
kana_to_hira("カタカナ")
# 'かたかな'
なぜこれが独立したライブラリとして存在するのか
音素化器 — 書かれた単語がどう発音されるかを推測するツール — には言語学的な判断が必要です。強勢の規則、例外、文脈依存の発音です。scriptconv はそれを意図的に一切持ちません。上記のすべての関数はテーブル参照かコードポイント計算です。同じ入力、同じ出力、推測なし、言語モデルなし、特定の言語が実際にどう聞こえるかについて間違い得るものは何もありません。これが、それを必要とするすべての音素化器が独自のバグを持つ独自の ARPABET テーブルを再実装する代わりに、これを共有することを安全にしているものです。音韻論スタック の記事は、実際に言語学的な意見を持つ発音推測エンジンが、この層を複製するのではなくどうその上に構築されているかを扱っています。
マッピングが正確でない場所
表記法間の変換が常に無損失であるとは限らず、scriptconv はこれを不意打ちとして残すのではなく問い合わせ可能なデータとして記録します。各表記法には独立して追跡される二つの特性があります。それを IPA に変換して戻すと元の記号が正確に再現されるか、そして IPA をそれに変換して戻すとすべての IPA 記号が再現されるかです。
ARPABET は両方向とも失敗します。制限された英語専用の音素目録を持っているため、IPA → ARPABET → IPA と進むと、ARPABET のテーブルに記号がない、IPA が作れる区別を失う可能性があります。X-SAMPA と Lexique は完全な IPA 目録を忠実にカバーしますが、自分たちの側から始めてきれいに往復することは保証されていません。Kirshenbaum と Buckwalter は自分たちの側から IPA へはきれいに往復しますが、逆はそうではありません。ハラビアラビア語音声化器の音声アルファベットである Mantoq は、IPA への一方向にのみ変換されます — 戻す変換器はありません。これらのどれも、どこかの docstring に埋もれてはいません。呼び出し側が往復が安全だと仮定する前に確認できるよう、このライブラリが公開しているデータです。
複数の出典からの発音データをつなぎ合わせている方、あるいは音素化器に届く前に文字体系を検出しテキストを正規化する必要がある方は、お問い合わせいただくか、サービスページでこの分野で私たちが作っている他のものをご覧ください。