Add files via upload
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2017 Keith Ito
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,59 @@
|
||||
""" from https://github.com/keithito/tacotron """
|
||||
from text import cleaners
|
||||
from text.symbols import symbols
|
||||
|
||||
|
||||
# Mappings from symbol to numeric ID and vice versa:
|
||||
_symbol_to_id = {s: i for i, s in enumerate(symbols)}
|
||||
_id_to_symbol = {i: s for i, s in enumerate(symbols)}
|
||||
|
||||
|
||||
def text_to_sequence(text, symbols, cleaner_names):
|
||||
'''Converts a string of text to a sequence of IDs corresponding to the symbols in the text.
|
||||
Args:
|
||||
text: string to convert to a sequence
|
||||
cleaner_names: names of the cleaner functions to run the text through
|
||||
Returns:
|
||||
List of integers corresponding to the symbols in the text
|
||||
'''
|
||||
sequence = []
|
||||
symbol_to_id = {s: i for i, s in enumerate(symbols)}
|
||||
clean_text = _clean_text(text, cleaner_names)
|
||||
print(clean_text)
|
||||
print(f" length:{len(clean_text)}")
|
||||
for symbol in clean_text:
|
||||
if symbol not in symbol_to_id.keys():
|
||||
continue
|
||||
symbol_id = symbol_to_id[symbol]
|
||||
sequence += [symbol_id]
|
||||
print(f" length:{len(sequence)}")
|
||||
return sequence
|
||||
|
||||
|
||||
def cleaned_text_to_sequence(cleaned_text):
|
||||
'''Converts a string of text to a sequence of IDs corresponding to the symbols in the text.
|
||||
Args:
|
||||
text: string to convert to a sequence
|
||||
Returns:
|
||||
List of integers corresponding to the symbols in the text
|
||||
'''
|
||||
sequence = [_symbol_to_id[symbol] for symbol in cleaned_text if symbol in _symbol_to_id.keys()]
|
||||
return sequence
|
||||
|
||||
|
||||
def sequence_to_text(sequence):
|
||||
'''Converts a sequence of IDs back to a string'''
|
||||
result = ''
|
||||
for symbol_id in sequence:
|
||||
s = _id_to_symbol[symbol_id]
|
||||
result += s
|
||||
return result
|
||||
|
||||
|
||||
def _clean_text(text, cleaner_names):
|
||||
for name in cleaner_names:
|
||||
cleaner = getattr(cleaners, name)
|
||||
if not cleaner:
|
||||
raise Exception('Unknown cleaner: %s' % name)
|
||||
text = cleaner(text)
|
||||
return text
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,59 @@
|
||||
import re
|
||||
import cn2an
|
||||
import opencc
|
||||
|
||||
|
||||
converter = opencc.OpenCC('jyutjyu')
|
||||
|
||||
# List of (Latin alphabet, ipa) pairs:
|
||||
_latin_to_ipa = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('A', 'ei˥'),
|
||||
('B', 'biː˥'),
|
||||
('C', 'siː˥'),
|
||||
('D', 'tiː˥'),
|
||||
('E', 'iː˥'),
|
||||
('F', 'e˥fuː˨˩'),
|
||||
('G', 'tsiː˥'),
|
||||
('H', 'ɪk̚˥tsʰyː˨˩'),
|
||||
('I', 'ɐi˥'),
|
||||
('J', 'tsei˥'),
|
||||
('K', 'kʰei˥'),
|
||||
('L', 'e˥llou˨˩'),
|
||||
('M', 'ɛːm˥'),
|
||||
('N', 'ɛːn˥'),
|
||||
('O', 'ou˥'),
|
||||
('P', 'pʰiː˥'),
|
||||
('Q', 'kʰiːu˥'),
|
||||
('R', 'aː˥lou˨˩'),
|
||||
('S', 'ɛː˥siː˨˩'),
|
||||
('T', 'tʰiː˥'),
|
||||
('U', 'juː˥'),
|
||||
('V', 'wiː˥'),
|
||||
('W', 'tʊk̚˥piː˥juː˥'),
|
||||
('X', 'ɪk̚˥siː˨˩'),
|
||||
('Y', 'waːi˥'),
|
||||
('Z', 'iː˨sɛːt̚˥')
|
||||
]]
|
||||
|
||||
|
||||
def number_to_cantonese(text):
|
||||
return re.sub(r'\d+(?:\.?\d+)?', lambda x: cn2an.an2cn(x.group()), text)
|
||||
|
||||
|
||||
def latin_to_ipa(text):
|
||||
for regex, replacement in _latin_to_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def cantonese_to_ipa(text):
|
||||
text = number_to_cantonese(text.upper())
|
||||
text = converter.convert(text).replace('-','').replace('$',' ')
|
||||
text = re.sub(r'[A-Z]', lambda x: latin_to_ipa(x.group())+' ', text)
|
||||
text = re.sub(r'[、;:]', ',', text)
|
||||
text = re.sub(r'\s*,\s*', ', ', text)
|
||||
text = re.sub(r'\s*。\s*', '. ', text)
|
||||
text = re.sub(r'\s*?\s*', '? ', text)
|
||||
text = re.sub(r'\s*!\s*', '! ', text)
|
||||
text = re.sub(r'\s*$', '', text)
|
||||
return text
|
||||
@@ -0,0 +1,128 @@
|
||||
import re
|
||||
from text.japanese import japanese_to_romaji_with_accent, japanese_to_ipa, japanese_to_ipa2, japanese_to_ipa3
|
||||
from text.korean import latin_to_hangul, number_to_hangul, divide_hangul, korean_to_lazy_ipa, korean_to_ipa
|
||||
from text.mandarin import number_to_chinese, chinese_to_bopomofo, latin_to_bopomofo, chinese_to_romaji, chinese_to_lazy_ipa, chinese_to_ipa, chinese_to_ipa2
|
||||
from text.sanskrit import devanagari_to_ipa
|
||||
from text.english import english_to_lazy_ipa, english_to_ipa2, english_to_lazy_ipa2
|
||||
from text.thai import num_to_thai, latin_to_thai
|
||||
# from text.shanghainese import shanghainese_to_ipa
|
||||
# from text.cantonese import cantonese_to_ipa
|
||||
# from text.ngu_dialect import ngu_dialect_to_ipa
|
||||
|
||||
|
||||
def japanese_cleaners(text):
|
||||
text = japanese_to_romaji_with_accent(text)
|
||||
text = re.sub(r'([A-Za-z])$', r'\1.', text)
|
||||
return text
|
||||
|
||||
|
||||
def japanese_cleaners2(text):
|
||||
return japanese_cleaners(text).replace('ts', 'ʦ').replace('...', '…')
|
||||
|
||||
|
||||
def korean_cleaners(text):
|
||||
'''Pipeline for Korean text'''
|
||||
text = latin_to_hangul(text)
|
||||
text = number_to_hangul(text)
|
||||
text = divide_hangul(text)
|
||||
text = re.sub(r'([\u3131-\u3163])$', r'\1.', text)
|
||||
return text
|
||||
|
||||
|
||||
def chinese_cleaners(text):
|
||||
'''Pipeline for Chinese text'''
|
||||
text = number_to_chinese(text)
|
||||
text = chinese_to_bopomofo(text)
|
||||
text = latin_to_bopomofo(text)
|
||||
text = re.sub(r'([ˉˊˇˋ˙])$', r'\1。', text)
|
||||
return text
|
||||
|
||||
|
||||
def zh_ja_mixture_cleaners(text):
|
||||
text = re.sub(r'\[ZH\](.*?)\[ZH\]',
|
||||
lambda x: chinese_to_romaji(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[JA\](.*?)\[JA\]', lambda x: japanese_to_romaji_with_accent(
|
||||
x.group(1)).replace('ts', 'ʦ').replace('u', 'ɯ').replace('...', '…')+' ', text)
|
||||
text = re.sub(r'\s+$', '', text)
|
||||
text = re.sub(r'([^\.,!\?\-…~])$', r'\1.', text)
|
||||
return text
|
||||
|
||||
|
||||
def sanskrit_cleaners(text):
|
||||
text = text.replace('॥', '।').replace('ॐ', 'ओम्')
|
||||
text = re.sub(r'([^।])$', r'\1।', text)
|
||||
return text
|
||||
|
||||
|
||||
def cjks_cleaners(text):
|
||||
text = re.sub(r'\[ZH\](.*?)\[ZH\]',
|
||||
lambda x: chinese_to_lazy_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[JA\](.*?)\[JA\]',
|
||||
lambda x: japanese_to_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[KO\](.*?)\[KO\]',
|
||||
lambda x: korean_to_lazy_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[SA\](.*?)\[SA\]',
|
||||
lambda x: devanagari_to_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[EN\](.*?)\[EN\]',
|
||||
lambda x: english_to_lazy_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\s+$', '', text)
|
||||
text = re.sub(r'([^\.,!\?\-…~])$', r'\1.', text)
|
||||
return text
|
||||
|
||||
|
||||
def cjke_cleaners(text):
|
||||
text = re.sub(r'\[ZH\](.*?)\[ZH\]', lambda x: chinese_to_lazy_ipa(x.group(1)).replace(
|
||||
'ʧ', 'tʃ').replace('ʦ', 'ts').replace('ɥan', 'ɥæn')+' ', text)
|
||||
text = re.sub(r'\[JA\](.*?)\[JA\]', lambda x: japanese_to_ipa(x.group(1)).replace('ʧ', 'tʃ').replace(
|
||||
'ʦ', 'ts').replace('ɥan', 'ɥæn').replace('ʥ', 'dz')+' ', text)
|
||||
text = re.sub(r'\[KO\](.*?)\[KO\]',
|
||||
lambda x: korean_to_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[EN\](.*?)\[EN\]', lambda x: english_to_ipa2(x.group(1)).replace('ɑ', 'a').replace(
|
||||
'ɔ', 'o').replace('ɛ', 'e').replace('ɪ', 'i').replace('ʊ', 'u')+' ', text)
|
||||
text = re.sub(r'\s+$', '', text)
|
||||
text = re.sub(r'([^\.,!\?\-…~])$', r'\1.', text)
|
||||
return text
|
||||
|
||||
|
||||
def cjke_cleaners2(text):
|
||||
text = re.sub(r'\[ZH\](.*?)\[ZH\]',
|
||||
lambda x: chinese_to_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[JA\](.*?)\[JA\]',
|
||||
lambda x: japanese_to_ipa2(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[KO\](.*?)\[KO\]',
|
||||
lambda x: korean_to_ipa(x.group(1))+' ', text)
|
||||
text = re.sub(r'\[EN\](.*?)\[EN\]',
|
||||
lambda x: english_to_ipa2(x.group(1))+' ', text)
|
||||
text = re.sub(r'\s+$', '', text)
|
||||
text = re.sub(r'([^\.,!\?\-…~])$', r'\1.', text)
|
||||
return text
|
||||
|
||||
|
||||
def thai_cleaners(text):
|
||||
text = num_to_thai(text)
|
||||
text = latin_to_thai(text)
|
||||
return text
|
||||
|
||||
|
||||
# def shanghainese_cleaners(text):
|
||||
# text = shanghainese_to_ipa(text)
|
||||
# text = re.sub(r'([^\.,!\?\-…~])$', r'\1.', text)
|
||||
# return text
|
||||
|
||||
|
||||
# def chinese_dialect_cleaners(text):
|
||||
# text = re.sub(r'\[ZH\](.*?)\[ZH\]',
|
||||
# lambda x: chinese_to_ipa2(x.group(1))+' ', text)
|
||||
# text = re.sub(r'\[JA\](.*?)\[JA\]',
|
||||
# lambda x: japanese_to_ipa3(x.group(1)).replace('Q', 'ʔ')+' ', text)
|
||||
# text = re.sub(r'\[SH\](.*?)\[SH\]', lambda x: shanghainese_to_ipa(x.group(1)).replace('1', '˥˧').replace('5',
|
||||
# '˧˧˦').replace('6', '˩˩˧').replace('7', '˥').replace('8', '˩˨').replace('ᴀ', 'ɐ').replace('ᴇ', 'e')+' ', text)
|
||||
# text = re.sub(r'\[GD\](.*?)\[GD\]',
|
||||
# lambda x: cantonese_to_ipa(x.group(1))+' ', text)
|
||||
# text = re.sub(r'\[EN\](.*?)\[EN\]',
|
||||
# lambda x: english_to_lazy_ipa2(x.group(1))+' ', text)
|
||||
# text = re.sub(r'\[([A-Z]{2})\](.*?)\[\1\]', lambda x: ngu_dialect_to_ipa(x.group(2), x.group(
|
||||
# 1)).replace('ʣ', 'dz').replace('ʥ', 'dʑ').replace('ʦ', 'ts').replace('ʨ', 'tɕ')+' ', text)
|
||||
# text = re.sub(r'\s+$', '', text)
|
||||
# text = re.sub(r'([^\.,!\?\-…~])$', r'\1.', text)
|
||||
# return text
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
""" from https://github.com/keithito/tacotron """
|
||||
|
||||
'''
|
||||
Cleaners are transformations that run over the input text at both training and eval time.
|
||||
|
||||
Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners"
|
||||
hyperparameter. Some cleaners are English-specific. You'll typically want to use:
|
||||
1. "english_cleaners" for English text
|
||||
2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using
|
||||
the Unidecode library (https://pypi.python.org/pypi/Unidecode)
|
||||
3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update
|
||||
the symbols in symbols.py to match your data).
|
||||
'''
|
||||
|
||||
|
||||
# Regular expression matching whitespace:
|
||||
|
||||
|
||||
import re
|
||||
import inflect
|
||||
from unidecode import unidecode
|
||||
import eng_to_ipa as ipa
|
||||
_inflect = inflect.engine()
|
||||
_comma_number_re = re.compile(r'([0-9][0-9\,]+[0-9])')
|
||||
_decimal_number_re = re.compile(r'([0-9]+\.[0-9]+)')
|
||||
_pounds_re = re.compile(r'£([0-9\,]*[0-9]+)')
|
||||
_dollars_re = re.compile(r'\$([0-9\.\,]*[0-9]+)')
|
||||
_ordinal_re = re.compile(r'[0-9]+(st|nd|rd|th)')
|
||||
_number_re = re.compile(r'[0-9]+')
|
||||
|
||||
# List of (regular expression, replacement) pairs for abbreviations:
|
||||
_abbreviations = [(re.compile('\\b%s\\.' % x[0], re.IGNORECASE), x[1]) for x in [
|
||||
('mrs', 'misess'),
|
||||
('mr', 'mister'),
|
||||
('dr', 'doctor'),
|
||||
('st', 'saint'),
|
||||
('co', 'company'),
|
||||
('jr', 'junior'),
|
||||
('maj', 'major'),
|
||||
('gen', 'general'),
|
||||
('drs', 'doctors'),
|
||||
('rev', 'reverend'),
|
||||
('lt', 'lieutenant'),
|
||||
('hon', 'honorable'),
|
||||
('sgt', 'sergeant'),
|
||||
('capt', 'captain'),
|
||||
('esq', 'esquire'),
|
||||
('ltd', 'limited'),
|
||||
('col', 'colonel'),
|
||||
('ft', 'fort'),
|
||||
]]
|
||||
|
||||
|
||||
# List of (ipa, lazy ipa) pairs:
|
||||
_lazy_ipa = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('r', 'ɹ'),
|
||||
('æ', 'e'),
|
||||
('ɑ', 'a'),
|
||||
('ɔ', 'o'),
|
||||
('ð', 'z'),
|
||||
('θ', 's'),
|
||||
('ɛ', 'e'),
|
||||
('ɪ', 'i'),
|
||||
('ʊ', 'u'),
|
||||
('ʒ', 'ʥ'),
|
||||
('ʤ', 'ʥ'),
|
||||
('ˈ', '↓'),
|
||||
]]
|
||||
|
||||
# List of (ipa, lazy ipa2) pairs:
|
||||
_lazy_ipa2 = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('r', 'ɹ'),
|
||||
('ð', 'z'),
|
||||
('θ', 's'),
|
||||
('ʒ', 'ʑ'),
|
||||
('ʤ', 'dʑ'),
|
||||
('ˈ', '↓'),
|
||||
]]
|
||||
|
||||
# List of (ipa, ipa2) pairs
|
||||
_ipa_to_ipa2 = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('r', 'ɹ'),
|
||||
('ʤ', 'dʒ'),
|
||||
('ʧ', 'tʃ')
|
||||
]]
|
||||
|
||||
|
||||
def expand_abbreviations(text):
|
||||
for regex, replacement in _abbreviations:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def collapse_whitespace(text):
|
||||
return re.sub(r'\s+', ' ', text)
|
||||
|
||||
|
||||
def _remove_commas(m):
|
||||
return m.group(1).replace(',', '')
|
||||
|
||||
|
||||
def _expand_decimal_point(m):
|
||||
return m.group(1).replace('.', ' point ')
|
||||
|
||||
|
||||
def _expand_dollars(m):
|
||||
match = m.group(1)
|
||||
parts = match.split('.')
|
||||
if len(parts) > 2:
|
||||
return match + ' dollars' # Unexpected format
|
||||
dollars = int(parts[0]) if parts[0] else 0
|
||||
cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0
|
||||
if dollars and cents:
|
||||
dollar_unit = 'dollar' if dollars == 1 else 'dollars'
|
||||
cent_unit = 'cent' if cents == 1 else 'cents'
|
||||
return '%s %s, %s %s' % (dollars, dollar_unit, cents, cent_unit)
|
||||
elif dollars:
|
||||
dollar_unit = 'dollar' if dollars == 1 else 'dollars'
|
||||
return '%s %s' % (dollars, dollar_unit)
|
||||
elif cents:
|
||||
cent_unit = 'cent' if cents == 1 else 'cents'
|
||||
return '%s %s' % (cents, cent_unit)
|
||||
else:
|
||||
return 'zero dollars'
|
||||
|
||||
|
||||
def _expand_ordinal(m):
|
||||
return _inflect.number_to_words(m.group(0))
|
||||
|
||||
|
||||
def _expand_number(m):
|
||||
num = int(m.group(0))
|
||||
if num > 1000 and num < 3000:
|
||||
if num == 2000:
|
||||
return 'two thousand'
|
||||
elif num > 2000 and num < 2010:
|
||||
return 'two thousand ' + _inflect.number_to_words(num % 100)
|
||||
elif num % 100 == 0:
|
||||
return _inflect.number_to_words(num // 100) + ' hundred'
|
||||
else:
|
||||
return _inflect.number_to_words(num, andword='', zero='oh', group=2).replace(', ', ' ')
|
||||
else:
|
||||
return _inflect.number_to_words(num, andword='')
|
||||
|
||||
|
||||
def normalize_numbers(text):
|
||||
text = re.sub(_comma_number_re, _remove_commas, text)
|
||||
text = re.sub(_pounds_re, r'\1 pounds', text)
|
||||
text = re.sub(_dollars_re, _expand_dollars, text)
|
||||
text = re.sub(_decimal_number_re, _expand_decimal_point, text)
|
||||
text = re.sub(_ordinal_re, _expand_ordinal, text)
|
||||
text = re.sub(_number_re, _expand_number, text)
|
||||
return text
|
||||
|
||||
|
||||
def mark_dark_l(text):
|
||||
return re.sub(r'l([^aeiouæɑɔəɛɪʊ ]*(?: |$))', lambda x: 'ɫ'+x.group(1), text)
|
||||
|
||||
|
||||
def english_to_ipa(text):
|
||||
text = unidecode(text).lower()
|
||||
text = expand_abbreviations(text)
|
||||
text = normalize_numbers(text)
|
||||
phonemes = ipa.convert(text)
|
||||
phonemes = collapse_whitespace(phonemes)
|
||||
return phonemes
|
||||
|
||||
|
||||
def english_to_lazy_ipa(text):
|
||||
text = english_to_ipa(text)
|
||||
for regex, replacement in _lazy_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def english_to_ipa2(text):
|
||||
text = english_to_ipa(text)
|
||||
text = mark_dark_l(text)
|
||||
for regex, replacement in _ipa_to_ipa2:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text.replace('...', '…')
|
||||
|
||||
|
||||
def english_to_lazy_ipa2(text):
|
||||
text = english_to_ipa(text)
|
||||
for regex, replacement in _lazy_ipa2:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
@@ -0,0 +1,153 @@
|
||||
import re
|
||||
from unidecode import unidecode
|
||||
import pyopenjtalk
|
||||
|
||||
|
||||
# Regular expression matching Japanese without punctuation marks:
|
||||
_japanese_characters = re.compile(
|
||||
r'[A-Za-z\d\u3005\u3040-\u30ff\u4e00-\u9fff\uff11-\uff19\uff21-\uff3a\uff41-\uff5a\uff66-\uff9d]')
|
||||
|
||||
# Regular expression matching non-Japanese characters or punctuation marks:
|
||||
_japanese_marks = re.compile(
|
||||
r'[^A-Za-z\d\u3005\u3040-\u30ff\u4e00-\u9fff\uff11-\uff19\uff21-\uff3a\uff41-\uff5a\uff66-\uff9d]')
|
||||
|
||||
# List of (symbol, Japanese) pairs for marks:
|
||||
_symbols_to_japanese = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('%', 'パーセント')
|
||||
]]
|
||||
|
||||
# List of (romaji, ipa) pairs for marks:
|
||||
_romaji_to_ipa = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('ts', 'ʦ'),
|
||||
('u', 'ɯ'),
|
||||
('j', 'ʥ'),
|
||||
('y', 'j'),
|
||||
('ni', 'n^i'),
|
||||
('nj', 'n^'),
|
||||
('hi', 'çi'),
|
||||
('hj', 'ç'),
|
||||
('f', 'ɸ'),
|
||||
('I', 'i*'),
|
||||
('U', 'ɯ*'),
|
||||
('r', 'ɾ')
|
||||
]]
|
||||
|
||||
# List of (romaji, ipa2) pairs for marks:
|
||||
_romaji_to_ipa2 = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('u', 'ɯ'),
|
||||
('ʧ', 'tʃ'),
|
||||
('j', 'dʑ'),
|
||||
('y', 'j'),
|
||||
('ni', 'n^i'),
|
||||
('nj', 'n^'),
|
||||
('hi', 'çi'),
|
||||
('hj', 'ç'),
|
||||
('f', 'ɸ'),
|
||||
('I', 'i*'),
|
||||
('U', 'ɯ*'),
|
||||
('r', 'ɾ')
|
||||
]]
|
||||
|
||||
# List of (consonant, sokuon) pairs:
|
||||
_real_sokuon = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
(r'Q([↑↓]*[kg])', r'k#\1'),
|
||||
(r'Q([↑↓]*[tdjʧ])', r't#\1'),
|
||||
(r'Q([↑↓]*[sʃ])', r's\1'),
|
||||
(r'Q([↑↓]*[pb])', r'p#\1')
|
||||
]]
|
||||
|
||||
# List of (consonant, hatsuon) pairs:
|
||||
_real_hatsuon = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
(r'N([↑↓]*[pbm])', r'm\1'),
|
||||
(r'N([↑↓]*[ʧʥj])', r'n^\1'),
|
||||
(r'N([↑↓]*[tdn])', r'n\1'),
|
||||
(r'N([↑↓]*[kg])', r'ŋ\1')
|
||||
]]
|
||||
|
||||
|
||||
def symbols_to_japanese(text):
|
||||
for regex, replacement in _symbols_to_japanese:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def japanese_to_romaji_with_accent(text):
|
||||
'''Reference https://r9y9.github.io/ttslearn/latest/notebooks/ch10_Recipe-Tacotron.html'''
|
||||
text = symbols_to_japanese(text)
|
||||
sentences = re.split(_japanese_marks, text)
|
||||
marks = re.findall(_japanese_marks, text)
|
||||
text = ''
|
||||
for i, sentence in enumerate(sentences):
|
||||
if re.match(_japanese_characters, sentence):
|
||||
if text != '':
|
||||
text += ' '
|
||||
labels = pyopenjtalk.extract_fullcontext(sentence)
|
||||
for n, label in enumerate(labels):
|
||||
phoneme = re.search(r'\-([^\+]*)\+', label).group(1)
|
||||
if phoneme not in ['sil', 'pau']:
|
||||
text += phoneme.replace('ch', 'ʧ').replace('sh',
|
||||
'ʃ').replace('cl', 'Q')
|
||||
else:
|
||||
continue
|
||||
# n_moras = int(re.search(r'/F:(\d+)_', label).group(1))
|
||||
a1 = int(re.search(r"/A:(\-?[0-9]+)\+", label).group(1))
|
||||
a2 = int(re.search(r"\+(\d+)\+", label).group(1))
|
||||
a3 = int(re.search(r"\+(\d+)/", label).group(1))
|
||||
if re.search(r'\-([^\+]*)\+', labels[n + 1]).group(1) in ['sil', 'pau']:
|
||||
a2_next = -1
|
||||
else:
|
||||
a2_next = int(
|
||||
re.search(r"\+(\d+)\+", labels[n + 1]).group(1))
|
||||
# Accent phrase boundary
|
||||
if a3 == 1 and a2_next == 1:
|
||||
text += ' '
|
||||
# Falling
|
||||
elif a1 == 0 and a2_next == a2 + 1:
|
||||
text += '↓'
|
||||
# Rising
|
||||
elif a2 == 1 and a2_next == 2:
|
||||
text += '↑'
|
||||
if i < len(marks):
|
||||
text += unidecode(marks[i]).replace(' ', '')
|
||||
return text
|
||||
|
||||
|
||||
def get_real_sokuon(text):
|
||||
for regex, replacement in _real_sokuon:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def get_real_hatsuon(text):
|
||||
for regex, replacement in _real_hatsuon:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def japanese_to_ipa(text):
|
||||
text = japanese_to_romaji_with_accent(text).replace('...', '…')
|
||||
text = re.sub(
|
||||
r'([aiueo])\1+', lambda x: x.group(0)[0]+'ː'*(len(x.group(0))-1), text)
|
||||
text = get_real_sokuon(text)
|
||||
text = get_real_hatsuon(text)
|
||||
for regex, replacement in _romaji_to_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def japanese_to_ipa2(text):
|
||||
text = japanese_to_romaji_with_accent(text).replace('...', '…')
|
||||
text = get_real_sokuon(text)
|
||||
text = get_real_hatsuon(text)
|
||||
for regex, replacement in _romaji_to_ipa2:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def japanese_to_ipa3(text):
|
||||
text = japanese_to_ipa2(text).replace('n^', 'ȵ').replace(
|
||||
'ʃ', 'ɕ').replace('*', '\u0325').replace('#', '\u031a')
|
||||
text = re.sub(
|
||||
r'([aiɯeo])\1+', lambda x: x.group(0)[0]+'ː'*(len(x.group(0))-1), text)
|
||||
text = re.sub(r'((?:^|\s)(?:ts|tɕ|[kpt]))', r'\1ʰ', text)
|
||||
return text
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
import re
|
||||
from jamo import h2j, j2hcj
|
||||
import ko_pron
|
||||
|
||||
|
||||
# This is a list of Korean classifiers preceded by pure Korean numerals.
|
||||
_korean_classifiers = '군데 권 개 그루 닢 대 두 마리 모 모금 뭇 발 발짝 방 번 벌 보루 살 수 술 시 쌈 움큼 정 짝 채 척 첩 축 켤레 톨 통'
|
||||
|
||||
# List of (hangul, hangul divided) pairs:
|
||||
_hangul_divided = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('ㄳ', 'ㄱㅅ'),
|
||||
('ㄵ', 'ㄴㅈ'),
|
||||
('ㄶ', 'ㄴㅎ'),
|
||||
('ㄺ', 'ㄹㄱ'),
|
||||
('ㄻ', 'ㄹㅁ'),
|
||||
('ㄼ', 'ㄹㅂ'),
|
||||
('ㄽ', 'ㄹㅅ'),
|
||||
('ㄾ', 'ㄹㅌ'),
|
||||
('ㄿ', 'ㄹㅍ'),
|
||||
('ㅀ', 'ㄹㅎ'),
|
||||
('ㅄ', 'ㅂㅅ'),
|
||||
('ㅘ', 'ㅗㅏ'),
|
||||
('ㅙ', 'ㅗㅐ'),
|
||||
('ㅚ', 'ㅗㅣ'),
|
||||
('ㅝ', 'ㅜㅓ'),
|
||||
('ㅞ', 'ㅜㅔ'),
|
||||
('ㅟ', 'ㅜㅣ'),
|
||||
('ㅢ', 'ㅡㅣ'),
|
||||
('ㅑ', 'ㅣㅏ'),
|
||||
('ㅒ', 'ㅣㅐ'),
|
||||
('ㅕ', 'ㅣㅓ'),
|
||||
('ㅖ', 'ㅣㅔ'),
|
||||
('ㅛ', 'ㅣㅗ'),
|
||||
('ㅠ', 'ㅣㅜ')
|
||||
]]
|
||||
|
||||
# List of (Latin alphabet, hangul) pairs:
|
||||
_latin_to_hangul = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [
|
||||
('a', '에이'),
|
||||
('b', '비'),
|
||||
('c', '시'),
|
||||
('d', '디'),
|
||||
('e', '이'),
|
||||
('f', '에프'),
|
||||
('g', '지'),
|
||||
('h', '에이치'),
|
||||
('i', '아이'),
|
||||
('j', '제이'),
|
||||
('k', '케이'),
|
||||
('l', '엘'),
|
||||
('m', '엠'),
|
||||
('n', '엔'),
|
||||
('o', '오'),
|
||||
('p', '피'),
|
||||
('q', '큐'),
|
||||
('r', '아르'),
|
||||
('s', '에스'),
|
||||
('t', '티'),
|
||||
('u', '유'),
|
||||
('v', '브이'),
|
||||
('w', '더블유'),
|
||||
('x', '엑스'),
|
||||
('y', '와이'),
|
||||
('z', '제트')
|
||||
]]
|
||||
|
||||
# List of (ipa, lazy ipa) pairs:
|
||||
_ipa_to_lazy_ipa = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [
|
||||
('t͡ɕ','ʧ'),
|
||||
('d͡ʑ','ʥ'),
|
||||
('ɲ','n^'),
|
||||
('ɕ','ʃ'),
|
||||
('ʷ','w'),
|
||||
('ɭ','l`'),
|
||||
('ʎ','ɾ'),
|
||||
('ɣ','ŋ'),
|
||||
('ɰ','ɯ'),
|
||||
('ʝ','j'),
|
||||
('ʌ','ə'),
|
||||
('ɡ','g'),
|
||||
('\u031a','#'),
|
||||
('\u0348','='),
|
||||
('\u031e',''),
|
||||
('\u0320',''),
|
||||
('\u0339','')
|
||||
]]
|
||||
|
||||
|
||||
def latin_to_hangul(text):
|
||||
for regex, replacement in _latin_to_hangul:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def divide_hangul(text):
|
||||
text = j2hcj(h2j(text))
|
||||
for regex, replacement in _hangul_divided:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def hangul_number(num, sino=True):
|
||||
'''Reference https://github.com/Kyubyong/g2pK'''
|
||||
num = re.sub(',', '', num)
|
||||
|
||||
if num == '0':
|
||||
return '영'
|
||||
if not sino and num == '20':
|
||||
return '스무'
|
||||
|
||||
digits = '123456789'
|
||||
names = '일이삼사오육칠팔구'
|
||||
digit2name = {d: n for d, n in zip(digits, names)}
|
||||
|
||||
modifiers = '한 두 세 네 다섯 여섯 일곱 여덟 아홉'
|
||||
decimals = '열 스물 서른 마흔 쉰 예순 일흔 여든 아흔'
|
||||
digit2mod = {d: mod for d, mod in zip(digits, modifiers.split())}
|
||||
digit2dec = {d: dec for d, dec in zip(digits, decimals.split())}
|
||||
|
||||
spelledout = []
|
||||
for i, digit in enumerate(num):
|
||||
i = len(num) - i - 1
|
||||
if sino:
|
||||
if i == 0:
|
||||
name = digit2name.get(digit, '')
|
||||
elif i == 1:
|
||||
name = digit2name.get(digit, '') + '십'
|
||||
name = name.replace('일십', '십')
|
||||
else:
|
||||
if i == 0:
|
||||
name = digit2mod.get(digit, '')
|
||||
elif i == 1:
|
||||
name = digit2dec.get(digit, '')
|
||||
if digit == '0':
|
||||
if i % 4 == 0:
|
||||
last_three = spelledout[-min(3, len(spelledout)):]
|
||||
if ''.join(last_three) == '':
|
||||
spelledout.append('')
|
||||
continue
|
||||
else:
|
||||
spelledout.append('')
|
||||
continue
|
||||
if i == 2:
|
||||
name = digit2name.get(digit, '') + '백'
|
||||
name = name.replace('일백', '백')
|
||||
elif i == 3:
|
||||
name = digit2name.get(digit, '') + '천'
|
||||
name = name.replace('일천', '천')
|
||||
elif i == 4:
|
||||
name = digit2name.get(digit, '') + '만'
|
||||
name = name.replace('일만', '만')
|
||||
elif i == 5:
|
||||
name = digit2name.get(digit, '') + '십'
|
||||
name = name.replace('일십', '십')
|
||||
elif i == 6:
|
||||
name = digit2name.get(digit, '') + '백'
|
||||
name = name.replace('일백', '백')
|
||||
elif i == 7:
|
||||
name = digit2name.get(digit, '') + '천'
|
||||
name = name.replace('일천', '천')
|
||||
elif i == 8:
|
||||
name = digit2name.get(digit, '') + '억'
|
||||
elif i == 9:
|
||||
name = digit2name.get(digit, '') + '십'
|
||||
elif i == 10:
|
||||
name = digit2name.get(digit, '') + '백'
|
||||
elif i == 11:
|
||||
name = digit2name.get(digit, '') + '천'
|
||||
elif i == 12:
|
||||
name = digit2name.get(digit, '') + '조'
|
||||
elif i == 13:
|
||||
name = digit2name.get(digit, '') + '십'
|
||||
elif i == 14:
|
||||
name = digit2name.get(digit, '') + '백'
|
||||
elif i == 15:
|
||||
name = digit2name.get(digit, '') + '천'
|
||||
spelledout.append(name)
|
||||
return ''.join(elem for elem in spelledout)
|
||||
|
||||
|
||||
def number_to_hangul(text):
|
||||
'''Reference https://github.com/Kyubyong/g2pK'''
|
||||
tokens = set(re.findall(r'(\d[\d,]*)([\uac00-\ud71f]+)', text))
|
||||
for token in tokens:
|
||||
num, classifier = token
|
||||
if classifier[:2] in _korean_classifiers or classifier[0] in _korean_classifiers:
|
||||
spelledout = hangul_number(num, sino=False)
|
||||
else:
|
||||
spelledout = hangul_number(num, sino=True)
|
||||
text = text.replace(f'{num}{classifier}', f'{spelledout}{classifier}')
|
||||
# digit by digit for remaining digits
|
||||
digits = '0123456789'
|
||||
names = '영일이삼사오육칠팔구'
|
||||
for d, n in zip(digits, names):
|
||||
text = text.replace(d, n)
|
||||
return text
|
||||
|
||||
|
||||
def korean_to_lazy_ipa(text):
|
||||
text = latin_to_hangul(text)
|
||||
text = number_to_hangul(text)
|
||||
text=re.sub('[\uac00-\ud7af]+',lambda x:ko_pron.romanise(x.group(0),'ipa').split('] ~ [')[0],text)
|
||||
for regex, replacement in _ipa_to_lazy_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def korean_to_ipa(text):
|
||||
text = korean_to_lazy_ipa(text)
|
||||
return text.replace('ʧ','tʃ').replace('ʥ','dʑ')
|
||||
@@ -0,0 +1,326 @@
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from pypinyin import lazy_pinyin, BOPOMOFO
|
||||
import jieba
|
||||
import cn2an
|
||||
import logging
|
||||
|
||||
|
||||
# List of (Latin alphabet, bopomofo) pairs:
|
||||
_latin_to_bopomofo = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [
|
||||
('a', 'ㄟˉ'),
|
||||
('b', 'ㄅㄧˋ'),
|
||||
('c', 'ㄙㄧˉ'),
|
||||
('d', 'ㄉㄧˋ'),
|
||||
('e', 'ㄧˋ'),
|
||||
('f', 'ㄝˊㄈㄨˋ'),
|
||||
('g', 'ㄐㄧˋ'),
|
||||
('h', 'ㄝˇㄑㄩˋ'),
|
||||
('i', 'ㄞˋ'),
|
||||
('j', 'ㄐㄟˋ'),
|
||||
('k', 'ㄎㄟˋ'),
|
||||
('l', 'ㄝˊㄛˋ'),
|
||||
('m', 'ㄝˊㄇㄨˋ'),
|
||||
('n', 'ㄣˉ'),
|
||||
('o', 'ㄡˉ'),
|
||||
('p', 'ㄆㄧˉ'),
|
||||
('q', 'ㄎㄧㄡˉ'),
|
||||
('r', 'ㄚˋ'),
|
||||
('s', 'ㄝˊㄙˋ'),
|
||||
('t', 'ㄊㄧˋ'),
|
||||
('u', 'ㄧㄡˉ'),
|
||||
('v', 'ㄨㄧˉ'),
|
||||
('w', 'ㄉㄚˋㄅㄨˋㄌㄧㄡˋ'),
|
||||
('x', 'ㄝˉㄎㄨˋㄙˋ'),
|
||||
('y', 'ㄨㄞˋ'),
|
||||
('z', 'ㄗㄟˋ')
|
||||
]]
|
||||
|
||||
# List of (bopomofo, romaji) pairs:
|
||||
_bopomofo_to_romaji = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('ㄅㄛ', 'p⁼wo'),
|
||||
('ㄆㄛ', 'pʰwo'),
|
||||
('ㄇㄛ', 'mwo'),
|
||||
('ㄈㄛ', 'fwo'),
|
||||
('ㄅ', 'p⁼'),
|
||||
('ㄆ', 'pʰ'),
|
||||
('ㄇ', 'm'),
|
||||
('ㄈ', 'f'),
|
||||
('ㄉ', 't⁼'),
|
||||
('ㄊ', 'tʰ'),
|
||||
('ㄋ', 'n'),
|
||||
('ㄌ', 'l'),
|
||||
('ㄍ', 'k⁼'),
|
||||
('ㄎ', 'kʰ'),
|
||||
('ㄏ', 'h'),
|
||||
('ㄐ', 'ʧ⁼'),
|
||||
('ㄑ', 'ʧʰ'),
|
||||
('ㄒ', 'ʃ'),
|
||||
('ㄓ', 'ʦ`⁼'),
|
||||
('ㄔ', 'ʦ`ʰ'),
|
||||
('ㄕ', 's`'),
|
||||
('ㄖ', 'ɹ`'),
|
||||
('ㄗ', 'ʦ⁼'),
|
||||
('ㄘ', 'ʦʰ'),
|
||||
('ㄙ', 's'),
|
||||
('ㄚ', 'a'),
|
||||
('ㄛ', 'o'),
|
||||
('ㄜ', 'ə'),
|
||||
('ㄝ', 'e'),
|
||||
('ㄞ', 'ai'),
|
||||
('ㄟ', 'ei'),
|
||||
('ㄠ', 'au'),
|
||||
('ㄡ', 'ou'),
|
||||
('ㄧㄢ', 'yeNN'),
|
||||
('ㄢ', 'aNN'),
|
||||
('ㄧㄣ', 'iNN'),
|
||||
('ㄣ', 'əNN'),
|
||||
('ㄤ', 'aNg'),
|
||||
('ㄧㄥ', 'iNg'),
|
||||
('ㄨㄥ', 'uNg'),
|
||||
('ㄩㄥ', 'yuNg'),
|
||||
('ㄥ', 'əNg'),
|
||||
('ㄦ', 'əɻ'),
|
||||
('ㄧ', 'i'),
|
||||
('ㄨ', 'u'),
|
||||
('ㄩ', 'ɥ'),
|
||||
('ˉ', '→'),
|
||||
('ˊ', '↑'),
|
||||
('ˇ', '↓↑'),
|
||||
('ˋ', '↓'),
|
||||
('˙', ''),
|
||||
(',', ','),
|
||||
('。', '.'),
|
||||
('!', '!'),
|
||||
('?', '?'),
|
||||
('—', '-')
|
||||
]]
|
||||
|
||||
# List of (romaji, ipa) pairs:
|
||||
_romaji_to_ipa = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [
|
||||
('ʃy', 'ʃ'),
|
||||
('ʧʰy', 'ʧʰ'),
|
||||
('ʧ⁼y', 'ʧ⁼'),
|
||||
('NN', 'n'),
|
||||
('Ng', 'ŋ'),
|
||||
('y', 'j'),
|
||||
('h', 'x')
|
||||
]]
|
||||
|
||||
# List of (bopomofo, ipa) pairs:
|
||||
_bopomofo_to_ipa = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('ㄅㄛ', 'p⁼wo'),
|
||||
('ㄆㄛ', 'pʰwo'),
|
||||
('ㄇㄛ', 'mwo'),
|
||||
('ㄈㄛ', 'fwo'),
|
||||
('ㄅ', 'p⁼'),
|
||||
('ㄆ', 'pʰ'),
|
||||
('ㄇ', 'm'),
|
||||
('ㄈ', 'f'),
|
||||
('ㄉ', 't⁼'),
|
||||
('ㄊ', 'tʰ'),
|
||||
('ㄋ', 'n'),
|
||||
('ㄌ', 'l'),
|
||||
('ㄍ', 'k⁼'),
|
||||
('ㄎ', 'kʰ'),
|
||||
('ㄏ', 'x'),
|
||||
('ㄐ', 'tʃ⁼'),
|
||||
('ㄑ', 'tʃʰ'),
|
||||
('ㄒ', 'ʃ'),
|
||||
('ㄓ', 'ts`⁼'),
|
||||
('ㄔ', 'ts`ʰ'),
|
||||
('ㄕ', 's`'),
|
||||
('ㄖ', 'ɹ`'),
|
||||
('ㄗ', 'ts⁼'),
|
||||
('ㄘ', 'tsʰ'),
|
||||
('ㄙ', 's'),
|
||||
('ㄚ', 'a'),
|
||||
('ㄛ', 'o'),
|
||||
('ㄜ', 'ə'),
|
||||
('ㄝ', 'ɛ'),
|
||||
('ㄞ', 'aɪ'),
|
||||
('ㄟ', 'eɪ'),
|
||||
('ㄠ', 'ɑʊ'),
|
||||
('ㄡ', 'oʊ'),
|
||||
('ㄧㄢ', 'jɛn'),
|
||||
('ㄩㄢ', 'ɥæn'),
|
||||
('ㄢ', 'an'),
|
||||
('ㄧㄣ', 'in'),
|
||||
('ㄩㄣ', 'ɥn'),
|
||||
('ㄣ', 'ən'),
|
||||
('ㄤ', 'ɑŋ'),
|
||||
('ㄧㄥ', 'iŋ'),
|
||||
('ㄨㄥ', 'ʊŋ'),
|
||||
('ㄩㄥ', 'jʊŋ'),
|
||||
('ㄥ', 'əŋ'),
|
||||
('ㄦ', 'əɻ'),
|
||||
('ㄧ', 'i'),
|
||||
('ㄨ', 'u'),
|
||||
('ㄩ', 'ɥ'),
|
||||
('ˉ', '→'),
|
||||
('ˊ', '↑'),
|
||||
('ˇ', '↓↑'),
|
||||
('ˋ', '↓'),
|
||||
('˙', ''),
|
||||
(',', ','),
|
||||
('。', '.'),
|
||||
('!', '!'),
|
||||
('?', '?'),
|
||||
('—', '-')
|
||||
]]
|
||||
|
||||
# List of (bopomofo, ipa2) pairs:
|
||||
_bopomofo_to_ipa2 = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('ㄅㄛ', 'pwo'),
|
||||
('ㄆㄛ', 'pʰwo'),
|
||||
('ㄇㄛ', 'mwo'),
|
||||
('ㄈㄛ', 'fwo'),
|
||||
('ㄅ', 'p'),
|
||||
('ㄆ', 'pʰ'),
|
||||
('ㄇ', 'm'),
|
||||
('ㄈ', 'f'),
|
||||
('ㄉ', 't'),
|
||||
('ㄊ', 'tʰ'),
|
||||
('ㄋ', 'n'),
|
||||
('ㄌ', 'l'),
|
||||
('ㄍ', 'k'),
|
||||
('ㄎ', 'kʰ'),
|
||||
('ㄏ', 'h'),
|
||||
('ㄐ', 'tɕ'),
|
||||
('ㄑ', 'tɕʰ'),
|
||||
('ㄒ', 'ɕ'),
|
||||
('ㄓ', 'tʂ'),
|
||||
('ㄔ', 'tʂʰ'),
|
||||
('ㄕ', 'ʂ'),
|
||||
('ㄖ', 'ɻ'),
|
||||
('ㄗ', 'ts'),
|
||||
('ㄘ', 'tsʰ'),
|
||||
('ㄙ', 's'),
|
||||
('ㄚ', 'a'),
|
||||
('ㄛ', 'o'),
|
||||
('ㄜ', 'ɤ'),
|
||||
('ㄝ', 'ɛ'),
|
||||
('ㄞ', 'aɪ'),
|
||||
('ㄟ', 'eɪ'),
|
||||
('ㄠ', 'ɑʊ'),
|
||||
('ㄡ', 'oʊ'),
|
||||
('ㄧㄢ', 'jɛn'),
|
||||
('ㄩㄢ', 'yæn'),
|
||||
('ㄢ', 'an'),
|
||||
('ㄧㄣ', 'in'),
|
||||
('ㄩㄣ', 'yn'),
|
||||
('ㄣ', 'ən'),
|
||||
('ㄤ', 'ɑŋ'),
|
||||
('ㄧㄥ', 'iŋ'),
|
||||
('ㄨㄥ', 'ʊŋ'),
|
||||
('ㄩㄥ', 'jʊŋ'),
|
||||
('ㄥ', 'ɤŋ'),
|
||||
('ㄦ', 'əɻ'),
|
||||
('ㄧ', 'i'),
|
||||
('ㄨ', 'u'),
|
||||
('ㄩ', 'y'),
|
||||
('ˉ', '˥'),
|
||||
('ˊ', '˧˥'),
|
||||
('ˇ', '˨˩˦'),
|
||||
('ˋ', '˥˩'),
|
||||
('˙', ''),
|
||||
(',', ','),
|
||||
('。', '.'),
|
||||
('!', '!'),
|
||||
('?', '?'),
|
||||
('—', '-')
|
||||
]]
|
||||
|
||||
|
||||
def number_to_chinese(text):
|
||||
numbers = re.findall(r'\d+(?:\.?\d+)?', text)
|
||||
for number in numbers:
|
||||
text = text.replace(number, cn2an.an2cn(number), 1)
|
||||
return text
|
||||
|
||||
|
||||
def chinese_to_bopomofo(text):
|
||||
text = text.replace('、', ',').replace(';', ',').replace(':', ',')
|
||||
words = jieba.lcut(text, cut_all=False)
|
||||
text = ''
|
||||
for word in words:
|
||||
bopomofos = lazy_pinyin(word, BOPOMOFO)
|
||||
if not re.search('[\u4e00-\u9fff]', word):
|
||||
text += word
|
||||
continue
|
||||
for i in range(len(bopomofos)):
|
||||
bopomofos[i] = re.sub(r'([\u3105-\u3129])$', r'\1ˉ', bopomofos[i])
|
||||
if text != '':
|
||||
text += ' '
|
||||
text += ''.join(bopomofos)
|
||||
return text
|
||||
|
||||
|
||||
def latin_to_bopomofo(text):
|
||||
for regex, replacement in _latin_to_bopomofo:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def bopomofo_to_romaji(text):
|
||||
for regex, replacement in _bopomofo_to_romaji:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def bopomofo_to_ipa(text):
|
||||
for regex, replacement in _bopomofo_to_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def bopomofo_to_ipa2(text):
|
||||
for regex, replacement in _bopomofo_to_ipa2:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def chinese_to_romaji(text):
|
||||
text = number_to_chinese(text)
|
||||
text = chinese_to_bopomofo(text)
|
||||
text = latin_to_bopomofo(text)
|
||||
text = bopomofo_to_romaji(text)
|
||||
text = re.sub('i([aoe])', r'y\1', text)
|
||||
text = re.sub('u([aoəe])', r'w\1', text)
|
||||
text = re.sub('([ʦsɹ]`[⁼ʰ]?)([→↓↑ ]+|$)',
|
||||
r'\1ɹ`\2', text).replace('ɻ', 'ɹ`')
|
||||
text = re.sub('([ʦs][⁼ʰ]?)([→↓↑ ]+|$)', r'\1ɹ\2', text)
|
||||
return text
|
||||
|
||||
|
||||
def chinese_to_lazy_ipa(text):
|
||||
text = chinese_to_romaji(text)
|
||||
for regex, replacement in _romaji_to_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def chinese_to_ipa(text):
|
||||
text = number_to_chinese(text)
|
||||
text = chinese_to_bopomofo(text)
|
||||
text = latin_to_bopomofo(text)
|
||||
text = bopomofo_to_ipa(text)
|
||||
text = re.sub('i([aoe])', r'j\1', text)
|
||||
text = re.sub('u([aoəe])', r'w\1', text)
|
||||
text = re.sub('([sɹ]`[⁼ʰ]?)([→↓↑ ]+|$)',
|
||||
r'\1ɹ`\2', text).replace('ɻ', 'ɹ`')
|
||||
text = re.sub('([s][⁼ʰ]?)([→↓↑ ]+|$)', r'\1ɹ\2', text)
|
||||
return text
|
||||
|
||||
|
||||
def chinese_to_ipa2(text):
|
||||
text = number_to_chinese(text)
|
||||
text = chinese_to_bopomofo(text)
|
||||
text = latin_to_bopomofo(text)
|
||||
text = bopomofo_to_ipa2(text)
|
||||
text = re.sub(r'i([aoe])', r'j\1', text)
|
||||
text = re.sub(r'u([aoəe])', r'w\1', text)
|
||||
text = re.sub(r'([ʂɹ]ʰ?)([˩˨˧˦˥ ]+|$)', r'\1ʅ\2', text)
|
||||
text = re.sub(r'(sʰ?)([˩˨˧˦˥ ]+|$)', r'\1ɿ\2', text)
|
||||
return text
|
||||
@@ -0,0 +1,30 @@
|
||||
import re
|
||||
import opencc
|
||||
|
||||
|
||||
dialects = {'SZ': 'suzhou', 'WX': 'wuxi', 'CZ': 'changzhou', 'HZ': 'hangzhou',
|
||||
'SX': 'shaoxing', 'NB': 'ningbo', 'JJ': 'jingjiang', 'YX': 'yixing',
|
||||
'JD': 'jiading', 'ZR': 'zhenru', 'PH': 'pinghu', 'TX': 'tongxiang',
|
||||
'JS': 'jiashan', 'HN': 'xiashi', 'LP': 'linping', 'XS': 'xiaoshan',
|
||||
'FY': 'fuyang', 'RA': 'ruao', 'CX': 'cixi', 'SM': 'sanmen',
|
||||
'TT': 'tiantai', 'WZ': 'wenzhou', 'SC': 'suichang', 'YB': 'youbu'}
|
||||
|
||||
converters = {}
|
||||
|
||||
for dialect in dialects.values():
|
||||
try:
|
||||
converters[dialect] = opencc.OpenCC(dialect)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def ngu_dialect_to_ipa(text, dialect):
|
||||
dialect = dialects[dialect]
|
||||
text = converters[dialect].convert(text).replace('-','').replace('$',' ')
|
||||
text = re.sub(r'[、;:]', ',', text)
|
||||
text = re.sub(r'\s*,\s*', ', ', text)
|
||||
text = re.sub(r'\s*。\s*', '. ', text)
|
||||
text = re.sub(r'\s*?\s*', '? ', text)
|
||||
text = re.sub(r'\s*!\s*', '! ', text)
|
||||
text = re.sub(r'\s*$', '', text)
|
||||
return text
|
||||
@@ -0,0 +1,62 @@
|
||||
import re
|
||||
from indic_transliteration import sanscript
|
||||
|
||||
|
||||
# List of (iast, ipa) pairs:
|
||||
_iast_to_ipa = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('a', 'ə'),
|
||||
('ā', 'aː'),
|
||||
('ī', 'iː'),
|
||||
('ū', 'uː'),
|
||||
('ṛ', 'ɹ`'),
|
||||
('ṝ', 'ɹ`ː'),
|
||||
('ḷ', 'l`'),
|
||||
('ḹ', 'l`ː'),
|
||||
('e', 'eː'),
|
||||
('o', 'oː'),
|
||||
('k', 'k⁼'),
|
||||
('k⁼h', 'kʰ'),
|
||||
('g', 'g⁼'),
|
||||
('g⁼h', 'gʰ'),
|
||||
('ṅ', 'ŋ'),
|
||||
('c', 'ʧ⁼'),
|
||||
('ʧ⁼h', 'ʧʰ'),
|
||||
('j', 'ʥ⁼'),
|
||||
('ʥ⁼h', 'ʥʰ'),
|
||||
('ñ', 'n^'),
|
||||
('ṭ', 't`⁼'),
|
||||
('t`⁼h', 't`ʰ'),
|
||||
('ḍ', 'd`⁼'),
|
||||
('d`⁼h', 'd`ʰ'),
|
||||
('ṇ', 'n`'),
|
||||
('t', 't⁼'),
|
||||
('t⁼h', 'tʰ'),
|
||||
('d', 'd⁼'),
|
||||
('d⁼h', 'dʰ'),
|
||||
('p', 'p⁼'),
|
||||
('p⁼h', 'pʰ'),
|
||||
('b', 'b⁼'),
|
||||
('b⁼h', 'bʰ'),
|
||||
('y', 'j'),
|
||||
('ś', 'ʃ'),
|
||||
('ṣ', 's`'),
|
||||
('r', 'ɾ'),
|
||||
('l̤', 'l`'),
|
||||
('h', 'ɦ'),
|
||||
("'", ''),
|
||||
('~', '^'),
|
||||
('ṃ', '^')
|
||||
]]
|
||||
|
||||
|
||||
def devanagari_to_ipa(text):
|
||||
text = text.replace('ॐ', 'ओम्')
|
||||
text = re.sub(r'\s*।\s*$', '.', text)
|
||||
text = re.sub(r'\s*।\s*', ', ', text)
|
||||
text = re.sub(r'\s*॥', '.', text)
|
||||
text = sanscript.transliterate(text, sanscript.DEVANAGARI, sanscript.IAST)
|
||||
for regex, replacement in _iast_to_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
text = re.sub('(.)[`ː]*ḥ', lambda x: x.group(0)
|
||||
[:-1]+'h'+x.group(1)+'*', text)
|
||||
return text
|
||||
@@ -0,0 +1,64 @@
|
||||
import re
|
||||
import cn2an
|
||||
import opencc
|
||||
|
||||
|
||||
converter = opencc.OpenCC('zaonhe')
|
||||
|
||||
# List of (Latin alphabet, ipa) pairs:
|
||||
_latin_to_ipa = [(re.compile('%s' % x[0]), x[1]) for x in [
|
||||
('A', 'ᴇ'),
|
||||
('B', 'bi'),
|
||||
('C', 'si'),
|
||||
('D', 'di'),
|
||||
('E', 'i'),
|
||||
('F', 'ᴇf'),
|
||||
('G', 'dʑi'),
|
||||
('H', 'ᴇtɕʰ'),
|
||||
('I', 'ᴀi'),
|
||||
('J', 'dʑᴇ'),
|
||||
('K', 'kʰᴇ'),
|
||||
('L', 'ᴇl'),
|
||||
('M', 'ᴇm'),
|
||||
('N', 'ᴇn'),
|
||||
('O', 'o'),
|
||||
('P', 'pʰi'),
|
||||
('Q', 'kʰiu'),
|
||||
('R', 'ᴀl'),
|
||||
('S', 'ᴇs'),
|
||||
('T', 'tʰi'),
|
||||
('U', 'ɦiu'),
|
||||
('V', 'vi'),
|
||||
('W', 'dᴀbɤliu'),
|
||||
('X', 'ᴇks'),
|
||||
('Y', 'uᴀi'),
|
||||
('Z', 'zᴇ')
|
||||
]]
|
||||
|
||||
|
||||
def _number_to_shanghainese(num):
|
||||
num = cn2an.an2cn(num).replace('一十','十').replace('二十', '廿').replace('二', '两')
|
||||
return re.sub(r'((?:^|[^三四五六七八九])十|廿)两', r'\1二', num)
|
||||
|
||||
|
||||
def number_to_shanghainese(text):
|
||||
return re.sub(r'\d+(?:\.?\d+)?', lambda x: _number_to_shanghainese(x.group()), text)
|
||||
|
||||
|
||||
def latin_to_ipa(text):
|
||||
for regex, replacement in _latin_to_ipa:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
|
||||
|
||||
def shanghainese_to_ipa(text):
|
||||
text = number_to_shanghainese(text.upper())
|
||||
text = converter.convert(text).replace('-','').replace('$',' ')
|
||||
text = re.sub(r'[A-Z]', lambda x: latin_to_ipa(x.group())+' ', text)
|
||||
text = re.sub(r'[、;:]', ',', text)
|
||||
text = re.sub(r'\s*,\s*', ', ', text)
|
||||
text = re.sub(r'\s*。\s*', '. ', text)
|
||||
text = re.sub(r'\s*?\s*', '? ', text)
|
||||
text = re.sub(r'\s*!\s*', '! ', text)
|
||||
text = re.sub(r'\s*$', '', text)
|
||||
return text
|
||||
@@ -0,0 +1,76 @@
|
||||
'''
|
||||
Defines the set of symbols used in text input to the model.
|
||||
'''
|
||||
|
||||
# japanese_cleaners
|
||||
# _pad = '_'
|
||||
# _punctuation = ',.!?-'
|
||||
# _letters = 'AEINOQUabdefghijkmnoprstuvwyzʃʧ↓↑ '
|
||||
|
||||
|
||||
'''# japanese_cleaners2
|
||||
_pad = '_'
|
||||
_punctuation = ',.!?-~…'
|
||||
_letters = 'AEINOQUabdefghijkmnoprstuvwyzʃʧʦ↓↑ '
|
||||
'''
|
||||
|
||||
|
||||
'''# korean_cleaners
|
||||
_pad = '_'
|
||||
_punctuation = ',.!?…~'
|
||||
_letters = 'ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎㄲㄸㅃㅆㅉㅏㅓㅗㅜㅡㅣㅐㅔ '
|
||||
'''
|
||||
|
||||
'''# chinese_cleaners
|
||||
_pad = '_'
|
||||
_punctuation = ',。!?—…'
|
||||
_letters = 'ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩˉˊˇˋ˙ '
|
||||
'''
|
||||
|
||||
# # zh_ja_mixture_cleaners
|
||||
# _pad = '_'
|
||||
# _punctuation = ',.!?-~…'
|
||||
# _letters = 'AEINOQUabdefghijklmnoprstuvwyzʃʧʦɯɹəɥ⁼ʰ`→↓↑ '
|
||||
|
||||
|
||||
'''# sanskrit_cleaners
|
||||
_pad = '_'
|
||||
_punctuation = '।'
|
||||
_letters = 'ँंःअआइईउऊऋएऐओऔकखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसहऽािीुूृॄेैोौ्ॠॢ '
|
||||
'''
|
||||
|
||||
'''# cjks_cleaners
|
||||
_pad = '_'
|
||||
_punctuation = ',.!?-~…'
|
||||
_letters = 'NQabdefghijklmnopstuvwxyzʃʧʥʦɯɹəɥçɸɾβŋɦː⁼ʰ`^#*=→↓↑ '
|
||||
'''
|
||||
|
||||
'''# thai_cleaners
|
||||
_pad = '_'
|
||||
_punctuation = '.!? '
|
||||
_letters = 'กขฃคฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลวศษสหฬอฮฯะัาำิีึืุูเแโใไๅๆ็่้๊๋์'
|
||||
'''
|
||||
|
||||
# # cjke_cleaners2
|
||||
_pad = '_'
|
||||
_punctuation = ',.!?-~…'
|
||||
_letters = 'NQabdefghijklmnopstuvwxyzɑæʃʑçɯɪɔɛɹðəɫɥɸʊɾʒθβŋɦ⁼ʰ`^#*=ˈˌ→↓↑ '
|
||||
|
||||
|
||||
'''# shanghainese_cleaners
|
||||
_pad = '_'
|
||||
_punctuation = ',.!?…'
|
||||
_letters = 'abdfghiklmnopstuvyzøŋȵɑɔɕəɤɦɪɿʑʔʰ̩̃ᴀᴇ15678 '
|
||||
'''
|
||||
|
||||
'''# chinese_dialect_cleaners
|
||||
_pad = '_'
|
||||
_punctuation = ',.!?~…─'
|
||||
_letters = '#Nabdefghijklmnoprstuvwxyzæçøŋœȵɐɑɒɓɔɕɗɘəɚɛɜɣɤɦɪɭɯɵɷɸɻɾɿʂʅʊʋʌʏʑʔʦʮʰʷˀː˥˦˧˨˩̥̩̃̚ᴀᴇ↑↓∅ⱼ '
|
||||
'''
|
||||
|
||||
# Export all symbols:
|
||||
symbols = [_pad] + list(_punctuation) + list(_letters)
|
||||
|
||||
# Special symbol ids
|
||||
SPACE_ID = symbols.index(" ")
|
||||
@@ -0,0 +1,44 @@
|
||||
import re
|
||||
from num_thai.thainumbers import NumThai
|
||||
|
||||
|
||||
num = NumThai()
|
||||
|
||||
# List of (Latin alphabet, Thai) pairs:
|
||||
_latin_to_thai = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [
|
||||
('a', 'เอ'),
|
||||
('b','บี'),
|
||||
('c','ซี'),
|
||||
('d','ดี'),
|
||||
('e','อี'),
|
||||
('f','เอฟ'),
|
||||
('g','จี'),
|
||||
('h','เอช'),
|
||||
('i','ไอ'),
|
||||
('j','เจ'),
|
||||
('k','เค'),
|
||||
('l','แอล'),
|
||||
('m','เอ็ม'),
|
||||
('n','เอ็น'),
|
||||
('o','โอ'),
|
||||
('p','พี'),
|
||||
('q','คิว'),
|
||||
('r','แอร์'),
|
||||
('s','เอส'),
|
||||
('t','ที'),
|
||||
('u','ยู'),
|
||||
('v','วี'),
|
||||
('w','ดับเบิลยู'),
|
||||
('x','เอ็กซ์'),
|
||||
('y','วาย'),
|
||||
('z','ซี')
|
||||
]]
|
||||
|
||||
|
||||
def num_to_thai(text):
|
||||
return re.sub(r'(?:\d+(?:,?\d+)?)+(?:\.\d+(?:,?\d+)?)?', lambda x: ''.join(num.NumberToTextThai(float(x.group(0).replace(',', '')))), text)
|
||||
|
||||
def latin_to_thai(text):
|
||||
for regex, replacement in _latin_to_thai:
|
||||
text = re.sub(regex, replacement, text)
|
||||
return text
|
||||
Reference in New Issue
Block a user