Restore 0.1.5 version from stash

This commit is contained in:
liaibo
2025-12-08 19:56:24 +08:00
parent de189e938d
commit 8db3f4e32d
8578 changed files with 2703426 additions and 217 deletions
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
from functools import wraps
# 存储各拼音风格对应的实现
_registry = {}
def convert(pinyin, style, strict, default=None, **kwargs):
"""根据拼音风格把原始拼音转换为不同的格式
:param pinyin: 原始有声调的单个拼音
:type pinyin: unicode
:param style: 拼音风格
:param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
是否严格遵照《汉语拼音方案》来处理声母和韵母,
详见 :ref:`strict`
:type strict: bool
:param default: 拼音风格对应的实现不存在时返回的默认值
:param kwargs: 兼容后续可能会新增的关键字参数。当前包含如下关键字参数:
``han``: 当前拼音对应的原始汉字。
:return: 按照拼音风格进行处理过后的拼音字符串
:rtype: unicode
"""
if style in _registry:
return _registry[style](pinyin, strict=strict, **kwargs)
return default
def register(style, func=None):
"""注册一个拼音风格实现。
自定义的函数应当使用 ``**kwargs`` 来兼容后续可能会新增的关键字参数,
当前默认会传递如下参数:
* ``pinyin``: 原始有声调的单个拼音
* ``strict``: 是否开启 strict 模式
* ``han``: 当前拼音对应的原始汉字
::
@register('echo')
def echo(pinyin, **kwargs):
return pinyin
# or
register('echo', echo)
"""
if func is not None:
_registry[style] = func
return
def decorator(func):
_registry[style] = func
@wraps(func)
def wrapper(pinyin, **kwargs):
return func(pinyin, **kwargs)
return wrapper
return decorator
def auto_discover():
"""自动注册内置的拼音风格实现"""
from pypinyin.style import ( # noqa
initials,
tone,
finals,
bopomofo,
cyrillic,
wadegiles,
others,
gwoyeu,
braille_mainland,
)
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from typing import Any, Optional, Callable, Dict, Text, Union
from pypinyin.constants import Style
TStyle = Style
TRegisterFunc = Optional[Callable[[Text, Dict[Any, Any]], Text]]
TWrapperFunc = Optional[Callable[[Text, Dict[Any, Any]], Text]]
_registry = {} # type: Dict[Union[TStyle, int, str, Any], TRegisterFunc]
def convert(pinyin: Text, style: TStyle, strict: bool,
default: Optional[Text] = ..., **kwargs: Any) -> Text: ...
def register(style: Union[TStyle, int, str, Any],
func: TRegisterFunc = ...) -> TWrapperFunc: ...
def auto_discover() -> None: ...
@@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import re
from pypinyin import phonetic_symbol
# 声母表
_INITIALS = [
'b',
'p',
'm',
'f',
'd',
't',
'n',
'l',
'g',
'k',
'h',
'j',
'q',
'x',
'zh',
'ch',
'sh',
'r',
'z',
'c',
's',
]
# 声母表, 把 y, w 也当作声母
_INITIALS_NOT_STRICT = _INITIALS + ['y', 'w']
# 韵母表
_FINALS = [
'i',
'u',
'ü',
'a',
'ia',
'ua',
'o',
'uo',
'e',
'ie',
'üe',
'ai',
'uai',
'ei',
'uei',
'ao',
'iao',
'ou',
'iou',
'an',
'ian',
'uan',
'üan',
'en',
'in',
'uen',
'ün',
'ang',
'iang',
'uang',
'eng',
'ing',
'ueng',
'ong',
'iong',
'er',
'ê',
]
# 带声调字符与数字表示声调的对应关系
PHONETIC_SYMBOL_DICT = phonetic_symbol.phonetic_symbol.copy()
PHONETIC_SYMBOL_DICT_KEY_LENGTH_NOT_ONE = dict(
(k, v)
for k, v in PHONETIC_SYMBOL_DICT.items()
if len(k) > 1
)
# 匹配带声调字符的正则表达式
RE_PHONETIC_SYMBOL = re.compile(
r'[{0}]'.format(
re.escape(''.join(x for x in PHONETIC_SYMBOL_DICT if len(x) == 1))
)
)
# 匹配使用数字标识声调的字符的正则表达式
RE_TONE2 = re.compile(r'([aeoiuvnmêü])([1-5])$')
# 匹配 TONE2 中标识韵母声调的正则表达式
RE_TONE3 = re.compile(r'^([a-zêü]+)([1-5])([a-zêü]*)$')
# 匹配单个数字
RE_NUMBER = re.compile(r'\d')
@@ -0,0 +1,22 @@
from typing import Any, List, Dict, Text
_INITIALS = ... # type: List[Text]
_INITIALS_NOT_STRICT = ... # type: List[Text]
_FINALS = ... # type: List[Text]
PHONETIC_SYMBOL_DICT = ... # type: Dict[Text, Text]
PHONETIC_SYMBOL_DICT_KEY_LENGTH_NOT_ONE = ... # type: Dict[Text, Text]
RE_PHONETIC_SYMBOL = ... # type : Any
RE_TONE2 = ... # type : Any
RE_TONE3 = ... # type : Any
RE_NUMBER = ... # type: Any
@@ -0,0 +1,577 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import re
from pypinyin import phonetic_symbol
from pypinyin.style._tone_rule import right_mark_index
from pypinyin.style._constants import RE_TONE3, RE_TONE2
from pypinyin.style.tone import converter
from pypinyin.style._utils import (
get_initials, replace_symbol_to_no_symbol,
get_finals, replace_symbol_to_number
)
_re_number = re.compile(r'\d')
def to_normal(pinyin, v_to_u=False):
"""将 :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:return: :py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_normal
>>> to_normal('zhōng')
'zhong'
>>> to_normal('zho1ng')
'zhong'
>>> to_normal('zhong1')
'zhong'
>>> to_normal('lüè')
'lve'
>>> to_normal('lüè', v_to_u=True)
'lüe'
"""
s = tone_to_tone2(pinyin, v_to_u=True)
s = tone2_to_normal(s)
return _fix_v_u(pinyin, s, v_to_u=v_to_u)
def to_tone(pinyin):
"""将 :py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:return: :py:attr:`~pypinyin.Style.TONE` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_tone
>>> to_tone('zho1ng')
'zhōng'
>>> to_tone('zhong1')
'zhōng'
"""
pinyin = pinyin.replace('v', 'ü')
if not _re_number.search(pinyin):
return pinyin
s = tone_to_tone2(pinyin)
s = tone2_to_tone(s)
return s
def to_tone2(pinyin, v_to_u=False, neutral_tone_with_five=False, **kwargs):
"""将 :py:attr:`~pypinyin.Style.TONE` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE2` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:param neutral_tone_with_five: 是否使用 ``5`` 标识轻声
:param kwargs: 用于兼容老版本的 ``neutral_tone_with_5`` 参数,当传入
``neutral_tone_with_5`` 参数时,
将覆盖 ``neutral_tone_with_five`` 的值。
:return: :py:attr:`~pypinyin.Style.TONE2` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_tone2
>>> to_tone2('zhōng')
'zho1ng'
>>> to_tone2('zhong1')
'zho1ng'
>>> to_tone2('shang')
'shang'
>>> to_tone2('shang', neutral_tone_with_five=True)
'sha5ng'
>>> to_tone2('lüè')
'lve4'
>>> to_tone2('lüè', v_to_u=True)
'lüe4'
"""
if kwargs.get('neutral_tone_with_5', None) is not None:
neutral_tone_with_five = kwargs['neutral_tone_with_5']
pinyin = pinyin.replace('5', '')
s = tone_to_tone3(
pinyin, v_to_u=True, neutral_tone_with_five=neutral_tone_with_five)
s = tone3_to_tone2(s)
return _fix_v_u(pinyin, s, v_to_u)
def to_tone3(pinyin, v_to_u=False, neutral_tone_with_five=False, **kwargs):
"""将 :py:attr:`~pypinyin.Style.TONE` 或
:py:attr:`~pypinyin.Style.TONE2` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE` 或
:py:attr:`~pypinyin.Style.TONE2` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:param neutral_tone_with_five: 是否使用 ``5`` 标识轻声
:param kwargs: 用于兼容老版本的 ``neutral_tone_with_5`` 参数,当传入
``neutral_tone_with_5`` 参数时,
将覆盖 ``neutral_tone_with_five`` 的值。
:return: :py:attr:`~pypinyin.Style.TONE2` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_tone3
>>> to_tone3('zhōng')
'zhong1'
>>> to_tone3('zho1ng')
'zhong1'
>>> to_tone3('shang')
'shang'
>>> to_tone3('shang', neutral_tone_with_five=True)
'shang5'
>>> to_tone3('lüè')
'lve4'
>>> to_tone3('lüè', v_to_u=True)
'lüe4'
"""
if kwargs.get('neutral_tone_with_5', None) is not None:
neutral_tone_with_five = kwargs['neutral_tone_with_5']
pinyin = pinyin.replace('5', '')
s = tone_to_tone2(
pinyin, v_to_u=True, neutral_tone_with_five=neutral_tone_with_five)
s = tone2_to_tone3(s)
return _fix_v_u(pinyin, s, v_to_u)
def to_initials(pinyin, strict=True):
"""将 :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 、
:py:attr:`~pypinyin.Style.TONE3` 或
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音转换为
:py:attr:`~pypinyin.Style.INITIALS` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 、
:py:attr:`~pypinyin.Style.TONE3` 或
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
:param strict: 返回结果是否严格遵照《汉语拼音方案》来处理声母和韵母,
详见 :ref:`strict`
:return: :py:attr:`~pypinyin.Style.INITIALS` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_initials
>>> to_initials('zhōng')
'zh'
"""
return get_initials(pinyin, strict=strict)
def to_finals(pinyin, strict=True, v_to_u=False):
"""将 :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 、
:py:attr:`~pypinyin.Style.TONE3` 或
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音转换为
:py:attr:`~pypinyin.Style.FINALS` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 、
:py:attr:`~pypinyin.Style.TONE3` 或
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
:param strict: 返回结果是否严格遵照《汉语拼音方案》来处理声母和韵母,
详见 :ref:`strict`
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:return: :py:attr:`~pypinyin.Style.FINALS` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_finals
>>> to_finals('zhōng')
'ong'
"""
new_pinyin = replace_symbol_to_no_symbol(pinyin).replace('v', 'ü')
finals = get_finals(new_pinyin, strict=strict)
finals = _fix_v_u(finals, finals, v_to_u)
return finals
def to_finals_tone(pinyin, strict=True):
"""将 :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.FINALS_TONE` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param strict: 返回结果是否严格遵照《汉语拼音方案》来处理声母和韵母,
详见 :ref:`strict`
:return: :py:attr:`~pypinyin.Style.FINALS_TONE` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_finals_tone
>>> to_finals_tone('zhōng')
'ōng'
"""
finals = to_finals_tone2(pinyin, strict=strict)
finals = tone2_to_tone(finals)
return finals
def to_finals_tone2(pinyin, strict=True, v_to_u=False,
neutral_tone_with_five=False):
"""将 :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.FINALS_TONE2` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param strict: 返回结果是否严格遵照《汉语拼音方案》来处理声母和韵母,
详见 :ref:`strict`
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:param neutral_tone_with_five: 是否使用 ``5`` 标识轻声
:return: :py:attr:`~pypinyin.Style.FINALS_TONE2` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_finals_tone2
>>> to_finals_tone2('zhōng')
'o1ng'
"""
pinyin = pinyin.replace('5', '')
finals = to_finals_tone3(pinyin, strict=strict, v_to_u=v_to_u,
neutral_tone_with_five=neutral_tone_with_five)
finals = tone3_to_tone2(finals, v_to_u=v_to_u)
return finals
def to_finals_tone3(pinyin, strict=True, v_to_u=False,
neutral_tone_with_five=False):
"""将 :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.FINALS_TONE3` 风格的拼音
:param pinyin: :py:attr:`~pypinyin.Style.TONE`、
:py:attr:`~pypinyin.Style.TONE2` 或
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param strict: 返回结果是否严格遵照《汉语拼音方案》来处理声母和韵母,
详见 :ref:`strict`
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:param neutral_tone_with_five: 是否使用 ``5`` 标识轻声
:return: :py:attr:`~pypinyin.Style.FINALS_TONE3` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import to_finals_tone3
>>> to_finals_tone3('zhōng')
'ong1'
"""
pinyin = pinyin.replace('5', '')
finals = to_finals(pinyin, strict=strict, v_to_u=v_to_u)
if not finals:
return finals
numbers = _re_number.findall(replace_symbol_to_number(pinyin))
if not numbers:
if neutral_tone_with_five:
numbers = ['5']
else:
return finals
number = numbers[0]
finals = finals + number
return finals
def tone_to_normal(tone, v_to_u=False):
"""将 :py:attr:`~pypinyin.Style.TONE` 风格的拼音转换为
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
:param tone: :py:attr:`~pypinyin.Style.TONE` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:return: :py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone_to_normal
>>> tone_to_normal('zhōng')
'zhong'
>>> tone_to_normal('lüè')
'lve'
>>> tone_to_normal('lüè', v_to_u=True)
'lüe'
"""
s = tone_to_tone2(tone, v_to_u=v_to_u)
s = _re_number.sub('', s)
return _v_to_u(s, v_to_u)
def tone_to_tone2(tone, v_to_u=False, neutral_tone_with_five=False, **kwargs):
"""将 :py:attr:`~pypinyin.Style.TONE` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE2` 风格的拼音
:param tone: :py:attr:`~pypinyin.Style.TONE` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:param neutral_tone_with_five: 是否使用 ``5`` 标识轻声
:param kwargs: 用于兼容老版本的 ``neutral_tone_with_5`` 参数,当传入
``neutral_tone_with_5`` 参数时,
将覆盖 ``neutral_tone_with_five`` 的值。
:return: :py:attr:`~pypinyin.Style.TONE2` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone_to_tone2
>>> tone_to_tone2('zhōng')
'zho1ng'
>>> tone_to_tone2('shang')
'shang'
>>> tone_to_tone2('shang', neutral_tone_with_5=True)
'sha5ng'
>>> tone_to_tone2('lüè')
'lve4'
>>> tone_to_tone2('lüè', v_to_u=True)
'lüe4'
"""
if kwargs.get('neutral_tone_with_5', None) is not None:
neutral_tone_with_five = kwargs['neutral_tone_with_5']
tone3 = tone_to_tone3(
tone, v_to_u=v_to_u, neutral_tone_with_five=neutral_tone_with_five)
s = tone3_to_tone2(tone3)
return _v_to_u(s, v_to_u)
def tone_to_tone3(tone, v_to_u=False, neutral_tone_with_five=False, **kwargs):
"""将 :py:attr:`~pypinyin.Style.TONE` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param tone: :py:attr:`~pypinyin.Style.TONE` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:param neutral_tone_with_five: 是否使用 ``5`` 标识轻声
:param kwargs: 用于兼容老版本的 ``neutral_tone_with_5`` 参数,当传入
``neutral_tone_with_5`` 参数时,
将覆盖 ``neutral_tone_with_five`` 的值。
:return: :py:attr:`~pypinyin.Style.TONE3` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone_to_tone3
>>> tone_to_tone3('zhōng')
'zhong1'
>>> tone_to_tone3('shang')
'shang'
>>> tone_to_tone3('shang', neutral_tone_with_five=True)
'shang5'
>>> tone_to_tone3('lüè')
'lve4'
>>> tone_to_tone3('lüè', v_to_u=True)
'lüe4'
"""
if kwargs.get('neutral_tone_with_5', None) is not None:
neutral_tone_with_five = kwargs['neutral_tone_with_5']
tone3 = converter.to_tone3(tone)
s = _improve_tone3(tone3, neutral_tone_with_five=neutral_tone_with_five)
return _v_to_u(s, v_to_u)
def tone2_to_normal(tone2, v_to_u=False):
"""将 :py:attr:`~pypinyin.Style.TONE2` 风格的拼音转换为
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
:param tone2: :py:attr:`~pypinyin.Style.TONE2` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:return: Style.NORMAL 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone2_to_normal
>>> tone2_to_normal('zho1ng')
'zhong'
>>> tone2_to_normal('lüe4')
'lve'
>>> tone2_to_normal('lüe4', v_to_u=True)
'lüe'
"""
s = _re_number.sub('', tone2)
s = _v_to_u(s, v_to_u)
return _fix_v_u(tone2, s, v_to_u=v_to_u)
def tone2_to_tone(tone2):
"""将 :py:attr:`~pypinyin.Style.TONE2` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE` 风格的拼音
:param tone2: :py:attr:`~pypinyin.Style.TONE2` 风格的拼音
:return: Style.TONE 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone2_to_tone
>>> tone2_to_tone('zho1ng')
'zhōng'
"""
regex = re.compile(RE_TONE2.pattern.replace('$', ''))
d = phonetic_symbol.phonetic_symbol_reverse
string = tone2.replace('ü', 'v').replace('5', '').replace('0', '')
def _replace(m):
s = m.group(0)
return d.get(s) or s
return regex.sub(_replace, string).replace('v', 'ü')
def tone2_to_tone3(tone2, v_to_u=False):
"""将 :py:attr:`~pypinyin.Style.TONE2` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param tone2: :py:attr:`~pypinyin.Style.TONE2` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:return: :py:attr:`~pypinyin.Style.TONE3` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone2_to_tone3
>>> tone2_to_tone3('zho1ng')
'zhong1'
>>> tone2_to_tone3('lüe4')
'lve4'
>>> tone2_to_tone3('lüe4', v_to_u=True)
'lüe4'
"""
tone3 = RE_TONE3.sub(r'\1\3\2', tone2)
return _fix_v_u(tone2, tone3, v_to_u=v_to_u)
def tone3_to_normal(tone3, v_to_u=False):
"""将 :py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
:param tone3: :py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:return: :py:attr:`~pypinyin.Style.NORMAL` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone3_to_normal
>>> tone3_to_normal('zhong1')
'zhong'
>>> tone3_to_normal('lüe4')
'lve'
>>> tone3_to_normal('lüe4', v_to_u=True)
'lüe'
"""
s = _re_number.sub('', tone3)
s = _v_to_u(s, v_to_u)
return _fix_v_u(tone3, s, v_to_u=v_to_u)
def tone3_to_tone(tone3):
"""将 :py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE` 风格的拼音
:param tone3: :py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:return: :py:attr:`~pypinyin.Style.TONE` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone3_to_tone
>>> tone3_to_tone('zhong1')
'zhōng'
"""
tone2 = tone3_to_tone2(tone3, v_to_u=True)
return tone2_to_tone(tone2)
def tone3_to_tone2(tone3, v_to_u=False):
"""将 :py:attr:`~pypinyin.Style.TONE3` 风格的拼音转换为
:py:attr:`~pypinyin.Style.TONE2` 风格的拼音
:param tone3: :py:attr:`~pypinyin.Style.TONE3` 风格的拼音
:param v_to_u: 是否使用 ``ü`` 代替原来的 ``v``,
当为 False 时结果中将使用 ``v`` 表示 ``ü``
:return: :py:attr:`~pypinyin.Style.TONE2` 风格的拼音
Usage::
>>> from pypinyin.contrib.tone_convert import tone3_to_tone2
>>> tone3_to_tone2('zhong1')
'zho1ng'
>>> tone3_to_tone2('lüe4')
'lve4'
>>> tone3_to_tone2('lüe4', v_to_u=True)
'lüe4'
"""
no_number_tone3 = tone3_to_normal(tone3)
mark_index = right_mark_index(no_number_tone3)
if mark_index is None:
mark_index = len(no_number_tone3) - 1
before = no_number_tone3[:mark_index + 1]
after = no_number_tone3[mark_index + 1:]
number = _get_number_from_pinyin(tone3)
if number is None:
return tone3
s = '{}{}{}'.format(before, number, after)
return _fix_v_u(tone3, s, v_to_u=v_to_u)
def _improve_tone3(tone3, neutral_tone_with_five=False):
number = _get_number_from_pinyin(tone3)
if number is None and neutral_tone_with_five and tone3 != '':
tone3 = '{}5'.format(tone3)
return tone3
def _get_number_from_pinyin(pinyin):
numbers = _re_number.findall(pinyin)
if numbers:
number = numbers[0]
else:
number = None
return number
def _v_to_u(pinyin, replace=False):
if not replace:
return pinyin
return pinyin.replace('v', 'ü')
def _fix_v_u(origin_py, new_py, v_to_u):
if not v_to_u:
return new_py.replace('ü', 'v')
return _v_to_u(new_py, replace=True)
@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
from typing import Any
from typing import Optional
from typing import Text
from typing import Tuple
_re_number = ... # type: Any
def to_normal(pinyin: Text, v_to_u: bool = ...) -> Text: ...
def to_tone(pinyin: Text) -> Text: ...
def to_tone2(pinyin: Text, v_to_u: bool = ..., neutral_tone_with_five: bool = ...) -> Text: ...
def to_tone3(pinyin: Text, v_to_u: bool = ..., neutral_tone_with_five: bool = ...) -> Text: ...
def to_initials(pinyin: Text, strict: bool = ...) -> Text: ...
def to_finals(pinyin: Text, strict: bool = ..., v_to_u: bool = ...) -> Text: ...
def to_finals_tone(pinyin: Text, strict: bool = ...) -> Text: ...
def to_finals_tone2(pinyin: Text, strict: bool = ..., v_to_u: bool = ..., neutral_tone_with_five: bool = ...) -> Text: ...
def to_finals_tone3(pinyin: Text, strict: bool = ..., v_to_u: bool = ..., neutral_tone_with_five: bool = ...) -> Text: ...
def tone_to_normal(tone: Text, v_to_u: bool = ...) -> Text: ...
def tone_to_tone2(tone: Text, v_to_u: bool = ..., neutral_tone_with_five: bool = ...) -> Text: ...
def tone_to_tone3(tone: Text, v_to_u: bool = ..., neutral_tone_with_five: bool = ...) -> Text: ...
def tone2_to_normal(tone2: Text, v_to_u: bool = ...) -> Text: ...
def tone2_to_tone(tone2: Text) -> Text: ...
def tone2_to_tone3(tone2: Text, v_to_u: bool = ...) -> Text: ...
def tone3_to_normal(tone3: Text, v_to_u: bool = ...) -> Text: ...
def tone3_to_tone(tone3: Text) -> Text: ...
def tone3_to_tone2(tone3: Text, v_to_u: bool = ...) -> Text: ...
def _improve_tone3(tone3: Text, neutral_tone_with_five: bool = ...) -> Text: ...
def _get_number_from_pinyin(pinyin: Text) -> Optional[int]: ...
def _v_to_u(pinyin: Text, replace: bool = ...) -> Text: ...
def _fix_v_u(origin_py: Text, new_py: Text, v_to_u: bool) -> Text: ...
@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
"""
标调位置
ɑ 不放过,
  没 ɑ 找 o、e
  ɑ、o、e、i、u、ü
  标调就按这顺序;
  i、u 若是连在一起,
  谁在后面就标谁。
http://www.hwjyw.com/resource/content/2010/06/04/8183.shtml
https://www.zhihu.com/question/23655297
https://github.com/mozillazg/python-pinyin/issues/160
http://www.pinyin.info/rules/where.html
"""
# TODO: 增加测试用例:使用 pinyin_dict 中的数据收集所有带声调拼音测试这个规则的正确性
# 1. 收集所有带声调拼音
# 2. 转换为数字声调拼音(tone3),然后再转换为声调拼音
# 3. 比对转换后的声调拼音跟原始拼音,确保结果一致
def right_mark_index(pinyin_no_tone):
# 'iou', 'uei', 'uen': 还原原始韵母后,还需要按照还原前的声调进行标记
if 'iou' in pinyin_no_tone:
return pinyin_no_tone.index('u')
if 'uei' in pinyin_no_tone:
return pinyin_no_tone.index('i')
if 'uen' in pinyin_no_tone:
return pinyin_no_tone.index('u')
# 有 ɑ 不放过, 没 ɑ 找 o、e
for c in ['a', 'o', 'e']:
if c in pinyin_no_tone:
return pinyin_no_tone.index(c) + len(c) - 1
# i、u 若是连在一起,谁在后面就标谁
for c in ['iu', 'ui']:
if c in pinyin_no_tone:
return pinyin_no_tone.index(c) + len(c) - 1
# ɑ、o、e、i、u、ü
for c in ['i', 'u', 'v', 'ü']:
if c in pinyin_no_tone:
return pinyin_no_tone.index(c) + len(c) - 1
# n, m, ê
for c in ['n', 'm', 'ê']:
if c in pinyin_no_tone:
return pinyin_no_tone.index(c) + len(c) - 1
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from typing import Text, Optional
def right_mark_index(pinyin_no_number: Text) -> Optional[int]: ...
@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from pypinyin.standard import convert_finals
from pypinyin.style._constants import (
_INITIALS, _INITIALS_NOT_STRICT, _FINALS,
RE_PHONETIC_SYMBOL, PHONETIC_SYMBOL_DICT,
PHONETIC_SYMBOL_DICT_KEY_LENGTH_NOT_ONE,
RE_NUMBER
)
def get_initials(pinyin, strict):
"""获取单个拼音中的声母.
:param pinyin: 单个拼音
:type pinyin: unicode
:param strict: 是否严格遵照《汉语拼音方案》来处理声母和韵母
:return: 声母
:rtype: unicode
"""
if strict:
_initials = _INITIALS
else:
_initials = _INITIALS_NOT_STRICT
for i in _initials:
if pinyin.startswith(i):
return i
return ''
def get_finals(pinyin, strict):
"""获取单个拼音中的韵母.
:param pinyin: 单个拼音,无声调拼音
:type pinyin: unicode
:param strict: 是否严格遵照《汉语拼音方案》来处理声母和韵母
:return: 韵母
:rtype: unicode
"""
if strict:
pinyin = convert_finals(pinyin)
initials = get_initials(pinyin, strict=strict) or ''
# 按声母分割,剩下的就是韵母
finals = pinyin[len(initials):]
# 处理既没有声母也没有韵母的情况
if strict and finals not in _FINALS:
# 处理 y, w 导致误判的问题,比如 yo
initials = get_initials(pinyin, strict=False)
finals = pinyin[len(initials):]
if finals in _FINALS:
return finals
return ''
# ń, ḿ
if not finals and not strict:
return pinyin
return finals
def replace_symbol_to_number(pinyin):
"""把声调替换为数字"""
def _replace(match):
symbol = match.group(0) # 带声调的字符
# 返回使用数字标识声调的字符
return PHONETIC_SYMBOL_DICT[symbol]
# 替换拼音中的带声调字符
value = RE_PHONETIC_SYMBOL.sub(_replace, pinyin)
for symbol, to in PHONETIC_SYMBOL_DICT_KEY_LENGTH_NOT_ONE.items():
value = value.replace(symbol, to)
return value
def replace_symbol_to_no_symbol(pinyin):
"""把带声调字符替换为没有声调的字符"""
value = replace_symbol_to_number(pinyin)
return RE_NUMBER.sub('', value)
def has_finals(pinyin):
"""判断是否有韵母"""
# 鼻音: 'm̄', 'ḿ', 'm̀', 'ń', 'ň', 'ǹ ' 没有韵母
for symbol in ['', 'ḿ', '', 'ń', 'ň', 'ǹ']:
if symbol in pinyin:
return False
return True
@@ -0,0 +1,15 @@
from typing import Text
def get_initials(pinyin: Text, strict: bool) -> Text: ...
def get_finals(pinyin: Text, strict: bool) -> Text: ...
def replace_symbol_to_number(pinyin: Text) -> Text: ...
def replace_symbol_to_no_symbol(pinyin: Text) -> Text: ...
def has_finals(pinyin: Text) -> bool: ...
@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
"""BOPOMOFO 相关的几个拼音风格实现:
Style.BOPOMOFO
Style.BOPOMOFO_FIRST
"""
from __future__ import unicode_literals
import re
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._constants import RE_TONE3
from pypinyin.style._utils import replace_symbol_to_number
# 注音转换表
BOPOMOFO_REPLACE = (
(re.compile(r'^m(\d)$'), 'mu\\1'), # 呣
(re.compile(r'^n(\d)$'), 'N\\1'), # 嗯
(re.compile(r'^r5$'), 'er5'), # 〜兒
(re.compile(r'iu'), 'iou'),
(re.compile(r'ui'), 'uei'),
(re.compile(r'ong'), 'ung'),
(re.compile(r'^yi?'), 'i'),
(re.compile(r'^wu?'), 'u'),
(re.compile(r'iu'), 'v'),
(re.compile(r'^([jqx])u'), '\\1v'),
(re.compile(r'([iuv])n'), '\\1en'),
(re.compile(r'^zhi?'), 'Z'),
(re.compile(r'^chi?'), 'C'),
(re.compile(r'^shi?'), 'S'),
(re.compile(r'^([zcsr])i'), '\\1'),
(re.compile(r'ai'), 'A'),
(re.compile(r'ei'), 'I'),
(re.compile(r'ao'), 'O'),
(re.compile(r'ou'), 'U'),
(re.compile(r'ang'), 'K'),
(re.compile(r'eng'), 'G'),
(re.compile(r'an'), 'M'),
(re.compile(r'en'), 'N'),
(re.compile(r'er'), 'R'),
(re.compile(r'eh'), 'E'),
(re.compile(r'([iv])e'), '\\1E'),
(re.compile(r'([^0-4])$'), '\\g<1>0'),
(re.compile(r'1$'), ''),
)
BOPOMOFO_TABLE = dict(zip(
'bpmfdtnlgkhjqxZCSrzcsiuvaoeEAIOUMNKGR2340ê',
'ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄧㄨㄩㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦˊˇˋ˙ㄝ'
))
class BopomofoConverter(object):
def to_bopomofo(self, pinyin, **kwargs):
pinyin = self._pre_convert(pinyin)
# 查表替换成注音
for find_re, replace in BOPOMOFO_REPLACE:
pinyin = find_re.sub(replace, pinyin)
pinyin = ''.join(BOPOMOFO_TABLE.get(x, x) for x in pinyin)
return pinyin
def to_bopomofo_first(self, pinyin, **kwargs):
pinyin = self.to_bopomofo(pinyin, **kwargs)
return pinyin[0]
def _pre_convert(self, pinyin):
# 用数字表示声调
pinyin = replace_symbol_to_number(pinyin)
# 将声调数字移动到最后
return RE_TONE3.sub(r'\1\3\2', pinyin)
converter = BopomofoConverter()
register(Style.BOPOMOFO, func=converter.to_bopomofo)
register(Style.BOPOMOFO_FIRST, func=converter.to_bopomofo_first)
@@ -0,0 +1,15 @@
from typing import Any, Dict, Tuple, Text
# 注音转换表
BOPOMOFO_REPLACE = ... # type: Tuple[Tuple[Any]]
BOPOMOFO_TABLE = ... # type: Dict[Text, Text]
class BopomofoConverter(object):
def to_bopomofo(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_bopomofo_first(self, pinyin: Text, **kwargs: Any) -> Text: ...
def _pre_convert(self, pinyin: Text) -> Text: ...
converter = ... # type: BopomofoConverter
@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
"""中国内地盲文相关的几个拼音风格实现:
Style.BRAILLE_MAINLAND
Style.BRAILLE_MAINLAND_TONE
https://en.wikipedia.org/wiki/Mainland_Chinese_Braille
"""
from __future__ import unicode_literals
import re
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._constants import RE_TONE3
from pypinyin.style._utils import (
replace_symbol_to_number, replace_symbol_to_no_symbol)
BRAILLE_MAINLAND_REPLACE = (
(re.compile(r'iu'), 'iou'),
(re.compile(r'ui'), 'uei'),
(re.compile(r'un'), 'uen'),
(re.compile(r'ong'), 'ung'),
(re.compile(r'^yi?'), 'i'),
(re.compile(r'^wu?'), 'u'),
(re.compile(r'y'), 'i'),
(re.compile(r'w'), 'u'),
(re.compile(r'iu'), 'v'),
(re.compile(r'^([jqx])u'), '\\1v'),
(re.compile(r'([iuv])n'), '\\1en'),
(re.compile(r'^zhi?'), 'Z'),
(re.compile(r'^chi?'), 'C'),
(re.compile(r'^shi?'), 'S'),
(re.compile(r'^([zcsr])i'), '\\1'),
(re.compile(r'iang'), ''),
(re.compile(r'uang'), ''),
(re.compile(r'ueng'), ''),
(re.compile(r'iong'), ''),
(re.compile(r'ang'), ''),
(re.compile(r'eng'), ''),
(re.compile(r'uai'), ''),
(re.compile(r'iao'), ''),
(re.compile(r'iou'), ''),
(re.compile(r'ian'), ''),
(re.compile(r'uan'), ''),
(re.compile(r'van'), ''),
(re.compile(r'uen'), ''),
(re.compile(r'ing'), ''),
(re.compile(r'ong'), ''),
(re.compile(r'er'), ''),
(re.compile(r'ai'), ''),
(re.compile(r'ei'), ''),
(re.compile(r'ao'), ''),
(re.compile(r'ou'), ''),
(re.compile(r'an'), ''),
(re.compile(r'en'), ''),
(re.compile(r'ia'), ''),
(re.compile(r'ua'), ''),
(re.compile(r'ie'), ''),
(re.compile(r'uo'), ''),
(re.compile(r've'), ''),
(re.compile(r'ui'), ''),
(re.compile(r'in'), ''),
(re.compile(r'vn'), ''),
)
BRAILLE_MAINLAND_TABLE = dict(zip(
'bpmfdtnlgkhjqxZCSrzcsiuvaoe1234',
'⠃⠏⠍⠋⠙⠞⠝⠇⠛⠅⠓⠛⠅⠓⠌⠟⠱⠚⠵⠉⠎⠊⠥⠬⠔⠢⠢⠁⠂⠄⠆'
))
class BrailleMainlandConverter(object):
def to_braille_mainland_tone(self, pinyin, **kwargs):
# 用数字表示声调
pinyin = replace_symbol_to_number(pinyin)
# 将声调数字移动到最后
pinyin = RE_TONE3.sub(r'\1\3\2', pinyin)
for find_re, replace in BRAILLE_MAINLAND_REPLACE:
pinyin = find_re.sub(replace, pinyin)
pinyin = ''.join(BRAILLE_MAINLAND_TABLE.get(x, x) for x in pinyin)
return pinyin
def to_braille_mainland(self, pinyin, **kwargs):
pinyin = replace_symbol_to_no_symbol(pinyin)
for find_re, replace in BRAILLE_MAINLAND_REPLACE:
pinyin = find_re.sub(replace, pinyin)
pinyin = ''.join(BRAILLE_MAINLAND_TABLE.get(x, x) for x in pinyin)
return pinyin
converter = BrailleMainlandConverter()
register(Style.BRAILLE_MAINLAND_TONE, func=converter.to_braille_mainland_tone)
register(Style.BRAILLE_MAINLAND, func=converter.to_braille_mainland)
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
"""中国内地盲文相关的几个拼音风格实现:
Style.BRAILLE_MAINLAND
Style.BRAILLE_MAINLAND_TONE
"""
from typing import Any, Dict, Tuple, Text
BRAILLE_MAINLAND_REPLACE = ... # type: Tuple[Tuple[Any]]
BRAILLE_MAINLAND_TABLE = ... # type: Dict[Text, Text]
class BrailleMainlandConverter(object):
def to_braille_mainland_tone(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_braille_mainland(self, pinyin: Text, **kwargs: Any) -> Text: ...
converter = ... # type: BrailleMainlandConverter
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
"""CYRILLIC 相关的几个拼音风格实现:
Style.CYRILLIC
Style.CYRILLIC_FIRST
"""
from __future__ import unicode_literals
import re
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._constants import RE_TONE3
from pypinyin.style._utils import replace_symbol_to_number
# 俄语转换表
CYRILLIC_REPLACE = (
(re.compile(r'ong'), 'ung'),
(re.compile(r'([zcs])i'), '\\1U'),
(re.compile(r'([xqj])u'), '\\1v'),
(re.compile(r'^wu(.?)$'), 'u\\1'),
(re.compile(r'(.+)r(.?)$'), '\\1R\\2'),
(re.compile(r'^zh'), 'Cr'),
(re.compile(r'^ch'), 'C'),
(re.compile(r'^j'), 'qZ'),
(re.compile(r'^z'), 'qZ'),
(re.compile(r'^x'), 's'),
(re.compile(r'^sh'), 'S'),
(re.compile(r'([^CSdst])uo'), '\\1o'),
(re.compile(r'^y(.*)$'), 'I\\1'),
(re.compile(r'Iai'), 'AI'),
(re.compile(r'Ia'), 'A'),
(re.compile(r'Ie'), 'E'),
(re.compile(r'Ii'), 'i'),
(re.compile(r'Iou'), 'V'),
(re.compile(r'Iu'), 'v'),
(re.compile(r'(.v)(\d?)$'), '\\1I\\2'),
(re.compile(r'Io'), 'O'),
(re.compile(r'iu'), 'v'),
(re.compile(r'ie'), 'E'),
(re.compile(r'hui'), 'huei'),
(re.compile(r'ui'), 'uI'),
(re.compile(r'ai'), 'aI'),
(re.compile(r'ei'), 'eI'),
(re.compile(r'ia'), 'A'),
(re.compile(r'(.*[^h])n([^g]?)$'), '\\1nM\\2'),
(re.compile(r'(.*[^h])ng(.?)$'), '\\1n\\2'),
(re.compile(r'^v(\d?$)'), 'vI'),
)
CYRILLIC_TABLE = dict(zip(
u'abwgdEOrZiIklmnopRstufhqcCSHTMUevAV',
u'абвгдеёжзийклмнопрстуфхццчшщъьыэюяю'
))
class CyrillicfoConverter(object):
def to_cyrillic(self, pinyin, **kwargs):
pinyin = self._pre_convert(pinyin)
# 查表替换成注音
for find_re, replace in CYRILLIC_REPLACE:
pinyin = find_re.sub(replace, pinyin)
pinyin = ''.join(CYRILLIC_TABLE.get(x, x) for x in pinyin)
return pinyin
def to_cyrillic_first(self, pinyin, **kwargs):
pinyin = self.to_cyrillic(pinyin, **kwargs)
return pinyin[0]
def _pre_convert(self, pinyin):
# 用数字表示声调
pinyin = replace_symbol_to_number(pinyin)
# 将声调数字移动到最后
return RE_TONE3.sub(r'\1\3\2', pinyin)
converter = CyrillicfoConverter()
register(Style.CYRILLIC, func=converter.to_cyrillic)
register(Style.CYRILLIC_FIRST, func=converter.to_cyrillic_first)
@@ -0,0 +1,16 @@
from typing import Any, Dict, Tuple, Text
# 俄语转换表
CYRILLIC_REPLACE = ... # type: Tuple[Tuple[Any]]
CYRILLIC_TABLE = ... # type: Dict[Text, Text]
class CyrillicfoConverter(object):
def to_cyrillic(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_cyrillic_first(self, pinyin: Text, **kwargs: Any) -> Text: ...
def _pre_convert(self, pinyin: Text) -> Text: ...
converter = ... # type: CyrillicfoConverter
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
"""韵母相关拼音风格:
Style.FINALS
Style.FINALS_TONE
Style.FINALS_TONE2
Style.FINALS_TONE3
"""
from __future__ import unicode_literals
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._tone_convert import (
to_finals, to_finals_tone, to_finals_tone2, to_finals_tone3
)
class FinalsConverter(object):
def to_finals(self, pinyin, **kwargs):
"""无声调韵母"""
return to_finals(pinyin, strict=kwargs.get('strict', True))
def to_finals_tone(self, pinyin, **kwargs):
"""声调在韵母头上"""
return to_finals_tone(pinyin, strict=kwargs.get('strict', True))
def to_finals_tone2(self, pinyin, **kwargs):
"""数字声调"""
return to_finals_tone2(pinyin, strict=kwargs.get('strict', True))
def to_finals_tone3(self, pinyin, **kwargs):
"""数字声调"""
return to_finals_tone3(pinyin, strict=kwargs.get('strict', True))
converter = FinalsConverter()
register(Style.FINALS, func=converter.to_finals)
register(Style.FINALS_TONE, func=converter.to_finals_tone)
register(Style.FINALS_TONE2, func=converter.to_finals_tone2)
register(Style.FINALS_TONE3, func=converter.to_finals_tone3)
@@ -0,0 +1,14 @@
from typing import Any, Text
class FinalsConverter(object):
def to_finals(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_finals_tone(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_finals_tone2(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_finals_tone3(self, pinyin: Text, **kwargs: Any) -> Text: ...
converter = ... # type: FinalsConverter
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import re
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._constants import RE_TONE3
from pypinyin.style._utils import replace_symbol_to_number
GWOYEU_REPLACE = (
(re.compile(r'^r5$'), 'er5'),
(re.compile(r'iu'), 'iou'),
(re.compile(r'ao'), 'au'),
(re.compile(r'^yi?'), 'i'),
(re.compile(r'^wu?'), 'u'),
(re.compile(r'^([jqx])u'), '\\1iu'),
(re.compile(r'(?<![iy])u([in])'), 'ue\\1'),
(re.compile(r'v'), 'iu'),
(re.compile(r'^([zcsr]h?)i'), '\\1y'),
(re.compile(r'^zh'), 'j'),
(re.compile(r'^z'), 'tz'),
(re.compile(r'^c(?!h)'), 'ts'),
(re.compile(r'^q'), 'ch'),
(re.compile(r'^x'), 'sh'),
(re.compile(r'er'), 'el'),
(re.compile(r'5$'), ''),
(re.compile(r'0$'), 'q'),
(re.compile(r'^i(.*[34])$'), 'yi\\1'),
(re.compile(r'^u(.*[34])$'), 'wu\\1'),
(re.compile(r'^yi([aeu].*4)$'), 'y\\1'),
(re.compile(r'^wu([ae].*4)$'), 'w\\1'),
)
TONE_REPLACE = (
(re.compile(r'^([lmnr])(.+)1$'), '\\1h\\2'),
(re.compile(r'1$'), ''),
(re.compile(r'^([lmnr])(.+)2$'), '\\1\\2'),
(re.compile(r'^([^ae]*)i(ng?)*2$'), '\\1yi\\2'),
(re.compile(r'^([^ao]*)u2$'), '\\1wu'),
(re.compile(r'^([^ae]*)i(.+)2$'), '\\1y\\2'),
(re.compile(r'^([^ao]*)u(.+)2$'), '\\1w\\2'),
(re.compile(r'([aeiouy]+)(.*)2$'), '\\1r\\2'),
(re.compile(r'^([^aeiou]*)([iu])(ng?)?3$'), '\\1\\2\\2\\3'),
(re.compile(r'^([^eu]*)i(.*)3$'), '\\1e\\2'),
(re.compile(r'^(.*)u(.*)3$'), '\\1o\\2'),
(re.compile(r'([aeiouy])(.*)3$'), '\\1\\1\\2'),
(re.compile(r'^([^ae]*)i4$'), '\\1ih'),
(re.compile(r'^([^ao]*)u4$'), '\\1uh'),
(re.compile(r'i4$'), 'y'),
(re.compile(r'u4$'), 'w'),
(re.compile(r'l4$'), 'll'),
(re.compile(r'ng4$'), 'nq'),
(re.compile(r'n4$'), 'nn'),
(re.compile(r'4$'), 'h'),
)
class GwoyeuConverter(object):
def _pre_convert(self, pinyin):
# 用数字表示声调
pinyin = replace_symbol_to_number(pinyin)
# 将声调数字移动到最后
return RE_TONE3.sub(r'\1\3\2', pinyin)
def to_gwoyeu(self, pinyin, **kwargs):
pinyin = self._pre_convert(pinyin)
for find_re, replace in GWOYEU_REPLACE:
pinyin = find_re.sub(replace, pinyin)
for find_re, replace in TONE_REPLACE:
if find_re.search(pinyin):
return find_re.sub(replace, pinyin)
return pinyin
converter = GwoyeuConverter()
register(Style.GWOYEU, func=converter.to_gwoyeu)
@@ -0,0 +1,10 @@
from typing import Any, Text, Tuple
GWOYEU_REPLACE = ... # type: Tuple[Tuple[Any]]
class GwoyeuConverter(object):
def to_wade_glides(self, pinyin: Text, **kwargs: Any) -> Text: ...
def _pre_convert(self, pinyin: Text) -> Text: ...
converter = ... # type: GwoyeuConverter
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
"""Style.INITIALS 风格"""
from __future__ import unicode_literals
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._utils import get_initials
@register(Style.INITIALS)
def convert(pinyin, **kwargs):
strict = kwargs.get('strict', True)
return get_initials(pinyin, strict)
@@ -0,0 +1,4 @@
from typing import Any, Text
def convert(pinyin: Text, **kwargs: Any) -> Text: ...
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
"""其他几个拼音风格实现:
Style.NORMAL
Style.FIRST_LETTER
"""
from __future__ import unicode_literals
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._utils import replace_symbol_to_no_symbol
class OthersConverter(object):
def to_normal(self, pinyin, **kwargs):
pinyin = replace_symbol_to_no_symbol(pinyin)
return pinyin
def to_first_letter(self, pinyin, **kwargs):
# 用数字表示声调
pinyin = self.to_normal(pinyin)
return pinyin[0]
converter = OthersConverter()
register(Style.NORMAL, func=converter.to_normal)
register(Style.FIRST_LETTER, func=converter.to_first_letter)
@@ -0,0 +1,10 @@
from typing import Any, Text
class OthersConverter(object):
def to_normal(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_first_letter(self, pinyin: Text, **kwargs: Any) -> Text: ...
converter = ... # type: OthersConverter
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
"""TONE 相关的几个拼音风格实现:
Style.TONE
Style.TONE2
Style.TONE3
"""
from __future__ import unicode_literals
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._constants import RE_TONE3
from pypinyin.style._utils import replace_symbol_to_number
class ToneConverter(object):
def to_tone(self, pinyin, **kwargs):
return pinyin
def to_tone2(self, pinyin, **kwargs):
# 用数字表示声调
pinyin = replace_symbol_to_number(pinyin)
return pinyin
def to_tone3(self, pinyin, **kwargs):
pinyin = self.to_tone2(pinyin, **kwargs)
# 将声调数字移动到最后
return RE_TONE3.sub(r'\1\3\2', pinyin)
converter = ToneConverter()
register(Style.TONE, func=converter.to_tone)
register(Style.TONE2, func=converter.to_tone2)
register(Style.TONE3, func=converter.to_tone3)
@@ -0,0 +1,12 @@
from typing import Any, Text
class ToneConverter(object):
def to_tone(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_tone2(self, pinyin: Text, **kwargs: Any) -> Text: ...
def to_tone3(self, pinyin: Text, **kwargs: Any) -> Text: ...
converter = ... # type: ToneConverter
@@ -0,0 +1,559 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from pypinyin.constants import Style
from pypinyin.style import register
from pypinyin.style._utils import replace_symbol_to_no_symbol
from pypinyin.style._utils import get_initials
# https://en.wikipedia.org/wiki/Wade%E2%80%93Giles
# https://web.archive.org/web/20070128065433/http://polaris.gseis.ucla.edu/skozerow/wadegiles.htm
# https://www.lib.uchicago.edu/about/directory/departments/eastasia/find/wade-giles-pinyin-conversion-table/
# https://www.zdic.net/ts/fulu/2019/05/18.html
_convert_table = [
['a', 'a'],
['ai', 'ai'],
['an', 'an'],
['ang', 'ang'],
['ao', 'ao'],
['zha', 'cha'],
['cha', 'ch\'a'],
['zhai', 'chai'],
['chai', 'ch\'ai'],
['zhan', 'chan'],
['chan', 'ch\'an'],
['zhang', 'chang'],
['chang', 'ch\'ang'],
['zhao', 'chao'],
['chao', 'ch\'ao'],
['zhe', 'che'],
['che', 'ch\'e'],
['zhen', 'chen'],
['chen', 'ch\'en'],
['zheng', 'cheng'],
['cheng', 'ch\'eng'],
['ji', 'chi'],
['qi', 'ch\'i'],
['jia', 'chia'],
['qia', 'ch\'ia'],
['jiang', 'chiang'],
['qiang', 'ch\'iang'],
['jiao', 'chiao'],
['qiao', 'ch\'iao'],
['jie', 'chieh'],
['qie', 'ch\'ieh'],
['jian', 'chien'],
['qian', 'ch\'ien'],
['zhi', 'chih'],
['chi', 'ch\'ih'],
['jin', 'chin'],
['qin', 'ch\'in'],
['jing', 'ching'],
['qing', 'ch\'ing'],
['jiu', 'chiu'],
['qiu', 'ch\'iu'],
['jiong', 'chiung'],
['qiong', 'ch\'iung'],
['zhuo', 'cho'],
['chuo', 'ch\'o'],
['zhou', 'chou'],
['chou', 'ch\'ou'],
['zhu', 'chu'],
['chu', 'ch\'u'],
['ju', 'chü'],
['qu', 'ch\'ü'],
['zhua', 'chua'],
['zhuai', 'chuai'],
['chuai', 'ch\'uai'],
['zhuan', 'chuan'],
['chuan', 'ch\'uan'],
['juan', 'chüan'],
['quan', 'ch\'üan'],
['zhuang', 'chuang'],
['chuang', 'ch\'uang'],
['jue', 'chüeh'],
['que', 'ch\'üeh'],
['zhui', 'chui'],
['chui', 'ch\'ui'],
['zhun', 'chun'],
['chun', 'ch\'un'],
['jun', 'chün'],
['qun', 'ch\'ün'],
['zhong', 'chung'],
['chong', 'ch\'ung'],
['en', 'en'],
['er', 'erh'],
['fa', 'fa'],
['fan', 'fan'],
['fang', 'fang'],
['fei', 'fei'],
['fen', 'fen'],
['feng', 'feng'],
['fo', 'fo'],
['fou', 'fou'],
['fu', 'fu'],
['ha', 'ha'],
['hai', 'hai'],
['han', 'han'],
['hang', 'hang'],
['hao', 'hao'],
['hei', 'hei'],
['hen', 'hen'],
['heng', 'heng'],
['he', 'ho'],
['hou', 'hou'],
['xi', 'hsi'],
['xia', 'hsia'],
['xiang', 'hsiang'],
['xiao', 'hsiao'],
['xie', 'hsieh'],
['xian', 'hsien'],
['xin', 'hsin'],
['xing', 'hsing'],
['xiu', 'hsiu'],
['xiong', 'hsiung'],
['xu', 'hsü'],
['xuan', 'hsüan'],
['xue', 'hsüeh'],
['xun', 'hsün'],
['hu', 'hu'],
['hua', 'hua'],
['huai', 'huai'],
['huan', 'huan'],
['huang', 'huang'],
['hui', 'hui'],
['hun', 'hun'],
['hong', 'hung'],
['huo', 'huo'],
['yi', 'i'],
['ran', 'jan'],
['rang', 'jang'],
['rao', 'jao'],
['re', 'je'],
['ren', 'jen'],
['reng', 'jeng'],
['ri', 'jih'],
['ruo', 'jo'],
['rou', 'jou'],
['ru', 'ju'],
['ruan', 'juan'],
['rui', 'jui'],
['run', 'jun'],
['rong', 'jung'],
['ga', 'ka'],
['ka', 'k\'a'],
['gai', 'kai'],
['kai', 'k\'ai'],
['gan', 'kan'],
['kan', 'k\'an'],
['gang', 'kang'],
['kang', 'k\'ang'],
['gao', 'kao'],
['kao', 'k\'ao'],
['gen', 'ken'],
['ken', 'k\'en'],
['geng', 'keng'],
['keng', 'k\'eng'],
['ge', 'ko'],
['ke', 'k\'o'],
['gou', 'kou'],
['kou', 'k\'ou'],
['gu', 'ku'],
['ku', 'k\'u'],
['gua', 'kua'],
['kua', 'k\'ua'],
['guai', 'kuai'],
['kuai', 'k\'uai'],
['guan', 'kuan'],
['kuan', 'k\'uan'],
['guang', 'kuang'],
['kuang', 'k\'uang'],
['gui', 'kuei'],
['kui', 'k\'uei'],
['gun', 'kun'],
['kun', 'k\'un'],
['gong', 'kung'],
['kong', 'k\'ung'],
['guo', 'kuo'],
['kuo', 'k\'uo'],
['la', 'la'],
['lai', 'lai'],
['lan', 'lan'],
['lang', 'lang'],
['lao', 'lao'],
['le', 'le'],
['lei', 'lei'],
['leng', 'leng'],
['li', 'li'],
['liang', 'liang'],
['liao', 'liao'],
['lie', 'lieh'],
['lian', 'lien'],
['lin', 'lin'],
['ling', 'ling'],
['liu', 'liu'],
['luo', 'lo'],
['lou', 'lou'],
['lu', 'lu'],
['', ''],
['luan', 'luan'],
['luan', 'lüan'],
['lue', 'lüeh'],
['lun', 'lun'],
['long', 'lung'],
['ma', 'ma'],
['mai', 'mai'],
['man', 'man'],
['mang', 'mang'],
['mao', 'mao'],
['mei', 'mei'],
['men', 'men'],
['meng', 'meng'],
['mi', 'mi'],
['miao', 'miao'],
['mie', 'mieh'],
['mian', 'mien'],
['min', 'min'],
['ming', 'ming'],
['miu', 'miu'],
['mo', 'mo'],
['mou', 'mou'],
['mu', 'mu'],
['na', 'na'],
['nai', 'nai'],
['nan', 'nan'],
['nang', 'nang'],
['nao', 'nao'],
['nei', 'nei'],
['nen', 'nen'],
['neng', 'neng'],
['ni', 'ni'],
['niang', 'niang'],
['niao', 'niao'],
['nie', 'nieh'],
['nian', 'nien'],
['nin', 'nin'],
['ning', 'ning'],
['niu', 'niu'],
['nuo', 'no'],
['nou', 'nou'],
['nu', 'nu'],
['', ''],
['nuan', 'nuan'],
['nue', 'nüeh'],
['nong', 'nung'],
['e', 'o'],
['ou', 'ou'],
['ba', 'pa'],
['pa', 'p\'a'],
['bai', 'pai'],
['pai', 'p\'ai'],
['ban', 'pan'],
['pan', 'p\'an'],
['bang', 'pang'],
['pang', 'p\'ang'],
['bao', 'pao'],
['pao', 'p\'ao'],
['bei', 'pei'],
['pei', 'p\'ei'],
['ben', 'pen'],
['pen', 'p\'en'],
['beng', 'peng'],
['peng', 'p\'eng'],
['bi', 'pi'],
['pi', 'p\'i'],
['biao', 'piao'],
['piao', 'p\'iao'],
['bie', 'pieh'],
['pie', 'p\'ieh'],
['bian', 'pien'],
['pian', 'p\'ien'],
['bin', 'pin'],
['pin', 'p\'in'],
['bing', 'ping'],
['ping', 'p\'ing'],
['bo', 'po'],
['po', 'p\'o'],
['pou', 'p\'ou'],
['bu', 'pu'],
['pu', 'p\'u'],
['sa', 'sa'],
['sai', 'sai'],
['san', 'san'],
['sang', 'sang'],
['sao', 'sao'],
['se', 'se'],
['sen', 'sen'],
['seng', 'seng'],
['sha', 'sha'],
['shai', 'shai'],
['shan', 'shan'],
['shang', 'shang'],
['shao', 'shao'],
['she', 'she'],
['shen', 'shen'],
['sheng', 'sheng'],
['shi', 'shih'],
['shou', 'shou'],
['shu', 'shu'],
['shua', 'shua'],
['shuai', 'shuai'],
['shuan', 'shuan'],
['shuang', 'shuang'],
['shui', 'shui'],
['shun', 'shun'],
['shuo', 'shuo'],
['suo', 'so'],
['sou', 'sou'],
['si', 'ssu'],
['su', 'su'],
['suan', 'suan'],
['sui', 'sui'],
['sun', 'sun'],
['song', 'sung'],
['da', 'ta'],
['ta', 't\'a'],
['dai', 'tai'],
['tai', 't\'ai'],
['dan', 'tan'],
['tan', 't\'an'],
['dang', 'tang'],
['tang', 't\'ang'],
['dao', 'tao'],
['tao', 't\'ao'],
['de', 'te'],
['te', 't\'e'],
['deng', 'teng'],
['teng', 't\'eng'],
['di', 'ti'],
['ti', 't\'i'],
['diao', 'tiao'],
['tiao', 't\'iao'],
['die', 'tieh'],
['tie', 't\'oeh'],
['dian', 'tien'],
['tian', 't\'ien'],
['ding', 'ting'],
['ting', 't\'ing'],
['diu', 'tiu'],
['duo', 'to'],
['tuo', 't\'o'],
['dou', 'tou'],
['tou', 't\'ou'],
['du', 'tu'],
['tu', 't\'u'],
['duan', 'tuan'],
['tuan', 't\'uan'],
['dui', 'tui'],
['tui', 't\'ui'],
['dun', 'tun'],
['tun', 't\'un'],
['dong', 'tung'],
['tong', 't\'ung'],
['za', 'tsa'],
['ca', 'ts\'a'],
['zai', 'tsai'],
['cai', 'ts\'ai'],
['zan', 'tsan'],
['can', 'ts\'an'],
['zang', 'tsang'],
['cang', 'ts\'ang'],
['zao', 'tsao'],
['cao', 'ts\'ao'],
['ze', 'tse'],
['ce', 'ts\'e'],
['zei', 'tsei'],
['zen', 'tsen'],
['cen', 'ts\'en'],
['zeng', 'tseng'],
['ceng', 'ts\'eng'],
['zuo', 'tso'],
['cuo', 'ts\'o'],
['zou', 'tsou'],
['cou', 'ts\'ou'],
['zu', 'tsu'],
['cu', 'ts\'u'],
['zuan', 'tsuan'],
['cuan', 'ts\'uan'],
['zui', 'tsui'],
['cui', 'ts\'ui'],
['zun', 'tsun'],
['cun', 'ts\'un'],
['zong', 'tsung'],
['cong', 'ts\'ung'],
['zi', 'tzu'],
['ci', 'tz\'u'],
['wa', 'wa'],
['wai', 'wai'],
['wan', 'wan'],
['wang', 'wang'],
['wei', 'wei'],
['wen', 'wen'],
['weng', 'weng'],
['wo', 'wo'],
['wu', 'wu'],
['ya', 'ya'],
['yai', 'yai'],
['yang', 'yang'],
['yao', 'yao'],
['ye', 'yeh'],
['yan', 'yen'],
['yin', 'yin'],
['ying', 'ying'],
['yo', 'yo'],
['you', 'yu'],
['yu', ''],
['yuan', 'yüan'],
['yue', 'yüeh'],
['yun', 'yün'],
['yong', 'yung'],
['chua', 'ch`ua'],
['dei', 'tei'],
['den', 'ten'],
['diang', 'tiang'],
['ei', 'ei'],
['eng', 'eng'],
['gei', 'kei'],
['lia', 'lia'],
['lo', 'lo'],
['lüan', 'lüan'],
['lvan', 'lüan'],
['lüe', 'lüeh'],
['lve', 'lüeh'],
['lün', 'lün'],
['lvn', 'lün'],
['me', 'me'],
['ne', 'ne'],
['nia', 'nia'],
['nun', 'nun'],
['nüe', 'nüeh'],
['nve', 'nüeh'],
['o', 'o'],
['sei', 'sei'],
['shei', 'shei'],
['shong', 'shung'],
['zhei', 'chei'],
]
_convert_table.sort(key=lambda x: len(x[0]), reverse=True)
# https://www.mysmth.net/nForum/#!article/Linguistics/4991
_initial_table = [
['b', 'p'],
['p', 'p\''],
['m', 'm'],
['f', 'f'],
['d', 't'],
['t', 't\''],
['n', 'n'],
['l', 'l'],
['g', 'g'],
['k', 'k\''],
['h', 'h'],
['j', 'ch'],
['q', 'ch\''],
['x', 'hs'],
['zh', 'ch'],
['ch', 'ch\''],
['sh', 'sh'],
['r', 'j'],
['z', 'ts'],
['c', 'ts\''],
['s', 's'],
]
_initial_table.sort(key=lambda x: len(x[0]), reverse=True)
_tone_table = [
['i', 'i'],
['u', 'u'],
['ü', 'ü'],
['v', 'ü'],
['a', 'a'],
['ia', 'ia'],
['ua', 'ua'],
['o', 'o'],
['uo', 'o'],
['e', 'e'],
['ie', 'ieh'],
['üe', 'üeh'],
['ve', 'üeh'],
['ai', 'ei'],
['uei', 'ui'],
['ao', 'ao'],
['iao', 'iao'],
['ou', 'ou'],
['iou', 'iu'],
['an', 'an'],
['ian', 'ien'],
['uan', 'uan'],
['üan', 'üan'],
['van', 'üan'],
['en', 'en'],
['in', 'in'],
['uen', 'un'],
['ün', 'ün'],
['vn', 'ün'],
['ang', 'ang'],
['iang', 'iang'],
['uang', 'uang'],
['eng', 'eng'],
['ing', 'ing'],
['ueng', 'ueng'],
['ong', 'ung'],
['iong', 'iung'],
['ê', 'eh'],
['er', 'erh'],
]
_tone_table.sort(key=lambda x: len(x[0]), reverse=True)
_except_table = [
['zhi', 'chih'],
['chi', 'ch\'ih'],
['shi', 'shih'],
['ri', 'jih'],
['zi', 'tzu'],
['ci', 'tz\'u'],
['si', 'ssu'],
['guo', 'guo'],
['kuo', 'k\'uo'],
['huo', 'huo'],
['luo', 'luo'],
['jue', 'chüeh'],
['que', 'ch\'üeh'],
['xue', 'hsüeh'],
]
_except_table.sort(key=lambda x: len(x[0]), reverse=True)
def to_wade_glides(pinyin, **kwargs):
pinyin = replace_symbol_to_no_symbol(pinyin).replace('v', 'ü')
whole_converted = _convert_whole(pinyin, _except_table)
if whole_converted != pinyin:
return _fixed_result(whole_converted)
whole_converted = _convert_whole(pinyin, _convert_table)
if whole_converted != pinyin:
return _fixed_result(whole_converted)
initials = get_initials(pinyin, strict=False)
tones = pinyin[len(initials):]
initials = _convert_whole(initials, _initial_table)
tones = _convert_whole(tones, _tone_table)
return _fixed_result('{}{}'.format(initials, tones))
def _fixed_result(pinyin):
return pinyin.replace('ü', 'v')
def _convert_whole(chars, table):
for pair in table:
f, r = pair
if f == chars:
return r
return chars
register(Style.WADEGILES, func=to_wade_glides)
@@ -0,0 +1,12 @@
from typing import Any, List, Dict, Text
_convert_table = ... # type: List[List[Text]]
_initial_table = ... # type: List[List[Text]]
_tone_table = ... # type: List[List[Text]]
_except_table = ... # type: List[List[Text]]
def to_wade_glides(pinyin: Text, **kwargs: Any) -> Text: ...