Американский словарь произношения говорит, что кошка (cat) звучит как K AE1 T.
Международный фонетический алфавит записывает тот же звук как kæt. Другая
система, только на ASCII, записывает его как k"{t. Все три описывают ровно одни и
те же две фонемы — звук «к», за которым следует краткое «а», за которым следует
«т». В звуке ничего не изменилось. Изменился только алфавит, использованный для его
записи.
Это постоянно случается с каждым, кто объединяет данные о произношении из более чем одного источника. Речевой датасет, построенный на американском словаре, использует одну нотацию. Европейский лексикон использует другую. Движок синтеза речи ожидает третью. Прежде чем такие данные можно будет объединить, найти или сравнить, их нужно перевести из одного фонетического алфавита в другой — та же работа, что делает переводчик между человеческими языками, только здесь «языки» — это способы записи звука, а не способы записи слов.
scriptconv — небольшая Python-библиотека, которая выполняет этот перевод, плюс
смежную задачу на уровень выше: определить, в какой системе письма вообще находится
фрагмент текста, прежде чем с ним можно будет что-либо ещё делать. У неё нет мнения
о лингвистике — она не угадывает, как произносится слово. Она только перемещает
символы, уже представляющие известные звуки, из одной нотации в другую, и определяет
системы письма по самим символам.
Несколько терминов, простыми словами
- Система письма (script): реальный набор символов, например латиница, кириллица или хангыль. Не то же самое, что язык: английский, французский и вьетнамский все используют латиницу, а сербский можно писать и кириллицей, и латиницей.
- Орфография: общепринятые правила написания для конкретного языка в данной системе письма — заглавные буквы, знаки ударения, пробелы.
- Фонема: отдельная единица звука в языке, например звук «к» в «кот».
- IPA (Международный фонетический алфавит): стандартный алфавит для точной записи звуков, независимый от обычной орфографии какого-либо языка.
- Транслитерация: преобразование текста из одной системы письма в другую путём отображения символов, нацеленное на точное сохранение исходного написания, а не произношения.
- Романизация: транслитерация конкретно в латиницу.
Зачем вообще существуют фонетические алфавиты только на ASCII
Для IPA нужны символы вроде ʃ, ʒ, ə и ˈ, которых нет на стандартной
клавиатуре. Это было реальной проблемой на протяжении десятилетий компьютерной
истории, до того как Unicode стал повсеместным и до того как большинство шрифтов,
терминалов и форматов файлов надёжно поддерживали текст не на ASCII.
Исследователи построили заменители только на ASCII: ARPABET, разработанный для
работы с распознаванием речи для американского английского, и X-SAMPA, ASCII-
кодировку полного IPA, разработанную безопасной для почты и старых терминалов. Это
не исторические курьёзы. 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'
Последний пример включает кинжальный алиф, маленькую надстрочную диакритику,
используемую в горстке слов (رحمٰن, рахман) — у Buckwalter есть конкретный
символ ASCII (`), зарезервированный для неё, отличный от обычного алифа, так
что транслитерация не схлопывает эти два символа.
Хангыль выглядит как блоки слогов, но каждый блок — это составленный кластер отдельных букв (джамо), уложенных в сетку — примерно как «Н», «А», «Н» визуально объединяются в один глиф для «хан», а не пишутся слева направо. Программному обеспечению, которому нужны отдельные буквы — для поиска, для фонологического анализа, для передачи в другую систему — приходится разбирать их обратно:
from scriptconv.translit import decompose_hangul
decompose_hangul("한국")
# 'ㅎㅏㄴㄱㅜㄱ'
decompose_hangul("국민")
# 'ㄱㅜㄱㅁㅣㄴ'
Последний пример важен тем, чего он не делает: 국민 (кунмин, «гражданин»)
произносится с носовой ассимиляцией, [ɡ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 может потерять различия, которые может выразить IPA, но для которых в таблице ARPABET нет символа. X-SAMPA и Lexique точно покрывают полный инвентарь IPA, но не гарантируют чистый круговой обход, начиная со своей стороны. Kirshenbaum и Buckwalter чисто проходят круговой обход со своей стороны в IPA, но не в обратную сторону. Mantoq, фонетический алфавит халабского арабского фонемизатора, конвертирует только в одну сторону, в IPA — обратного конвертера нет. Ничто из этого не спрятано где-то в docstring; это данные, которые библиотека раскрывает, чтобы вызывающая сторона могла проверить, прежде чем предполагать, что круговой обход безопасен.
Если вы сшиваете вместе данные о произношении из нескольких источников или вам нужно определять системы письма и нормализовать текст перед тем, как он попадёт в фонемизатор, свяжитесь с нами или посмотрите, что ещё мы строим в этой области, на странице услуг.