| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- # -*- coding: utf-8 -*-
- from __future__ import unicode_literals
- from copy import deepcopy
- from pypinyin.compat import text_type, callable_check
- from pypinyin.constants import (
- PHRASES_DICT, PINYIN_DICT,
- RE_HANS
- )
- from pypinyin.contrib.uv import V2UMixin
- from pypinyin.contrib.neutral_tone import NeutralToneWith5Mixin
- from pypinyin.contrib.tone_sandhi import ToneSandhiMixin
- from pypinyin.exceptions import PinyinNotFoundException
- from pypinyin.utils import _remove_dup_and_empty
- from pypinyin.style import auto_discover
- from pypinyin.style import convert as convert_style
- auto_discover()
- class Converter(object):
- def convert(self, words, style, heteronym, errors, strict, **kwargs):
- # TODO: use ``abc`` module
- raise NotImplementedError # pragma: no cover
- class DefaultConverter(Converter):
- def __init__(self, **kwargs):
- pass
- def convert(self, words, style, heteronym, errors, strict, **kwargs):
- """根据参数把汉字转成相应风格的拼音结果。
- :param words: 汉字字符串
- :type words: unicode
- :param style: 拼音风格
- :param heteronym: 是否启用多音字
- :type heteronym: bool
- :param errors: 如何处理没有拼音的字符
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :type strict: bool
- :return: 按风格转换后的拼音结果
- :rtype: list
- """
- pys = []
- # 初步过滤没有拼音的字符
- if RE_HANS.match(words):
- pys = self._phrase_pinyin(words, style=style, heteronym=heteronym,
- errors=errors, strict=strict)
- post_data = self.post_pinyin(words, heteronym, pys)
- if post_data is not None:
- pys = post_data
- pys = self.convert_styles(
- pys, words, style, heteronym, errors, strict)
- else:
- py = self.handle_nopinyin(words, style=style, errors=errors,
- heteronym=heteronym, strict=strict)
- if py:
- pys.extend(py)
- return _remove_dup_and_empty(pys)
- def pre_convert_style(self, han, orig_pinyin, style, strict, **kwargs):
- """在把原始带声调的拼音按拼音风格转换前会调用 ``pre_convert_style`` 方法。
- 如果返回值不为 ``None`` 会使用返回的结果代替 ``orig_pinyin``
- 来进行后面的风格转换。
- :param han: 要处理的汉字
- :param orig_pinyin: 汉字对应的原始带声调拼音
- :param style: 要转换的拼音风格
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :param kwargs: 其他关键字参数,暂时无用,用于以后扩展新的参数。
- :return: ``None`` 或代替 ``orig_pinyin`` 参与拼音风格转换的拼音字符串。
- """
- pass
- def convert_style(self, han, orig_pinyin, style, strict, **kwargs):
- """按 ``style`` 的值对 ``orig_pinyin`` 进行处理,返回处理后的拼音
- 转换风格前会调用 ``pre_convert_style`` 方法,
- 转换后会调用 ``post_convert_style`` 方法。
- :param han: 要处理的单个汉字
- :param orig_pinyin: 汉字对应的原始带声调拼音
- :param style: 拼音风格
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :param kwargs: 其他关键字参数,暂时无用,用于以后扩展新的参数。
- :return: 按拼音风格转换处理后的拼音
- """
- pre_data = self.pre_convert_style(
- han, orig_pinyin, style=style, strict=strict)
- if pre_data is not None:
- pinyin = pre_data
- else:
- pinyin = orig_pinyin
- converted_pinyin = self._convert_style(
- han, pinyin, style=style, strict=strict, default=pinyin)
- post_data = self.post_convert_style(
- han, pinyin, converted_pinyin, style=style, strict=strict)
- if post_data is None:
- post_data = converted_pinyin
- return post_data
- def post_convert_style(self, han, orig_pinyin, converted_pinyin,
- style, strict, **kwargs):
- """在把原始带声调的拼音按拼音风格转换前会调用 ``pre_convert_style`` 方法。
- 如果返回值不为 ``None`` 会使用返回的结果代替 ``converted_pinyin``
- 作为拼音风格转换后的最终拼音结果。
- :param han: 要处理的汉字
- :param orig_pinyin: 汉字对应的原始带声调拼音
- :param converted_pinyin: 按拼音风格转换处理后的拼音
- :param style: 要转换的拼音风格
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :param kwargs: 其他关键字参数,暂时无用,用于以后扩展新的参数。
- :return: ``None`` 或代替 ``converted_pinyin`` 作为拼音风格转换后的拼音结果。
- """
- pass
- def pre_handle_nopinyin(self, chars, style, heteronym, errors,
- strict, **kwargs):
- """处理没有拼音的字符串前会调用 ``pre_handle_nopinyin`` 方法。
- 如果返回值不为 ``None`` 会使用返回的结果作为处理没有拼音字符串的结果,
- 不再使用内置方法进行处理。
- :param chars: 待处理的没有拼音的字符串
- :param errors: 如何处理
- :param heteronym: 是否需要处理多音字
- :param kwargs: 其他关键字参数,暂时无用,用于以后扩展新的参数。
- :return: ``None`` 或代替 ``chars`` 参与拼音风格转换的拼音字符串
- 或拼音结果 list。
- """
- pass
- def handle_nopinyin(self, chars, style, heteronym, errors,
- strict, **kwargs):
- """处理没有拼音的字符串。
- 处理前会调用 ``pre_handle_nopinyin`` 方法,
- 处理后会调用 ``post_handle_nopinyin`` 方法。
- :param chars: 待处理的没有拼音的字符串
- :param style: 拼音风格
- :param errors: 如何处理
- :param heteronym: 是否需要处理多音字
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :return: 处理后的拼音结果,如果为 ``None`` 或空 list 表示忽略这个字符串.
- :rtype: list
- """
- pre_data = self.pre_handle_nopinyin(
- chars, style, errors=errors, heteronym=heteronym, strict=strict)
- if pre_data is not None:
- py = pre_data
- else:
- pre_data = chars
- py = self._convert_nopinyin_chars(
- pre_data, style, errors=errors,
- heteronym=heteronym, strict=strict)
- post_data = self.post_handle_nopinyin(
- chars, style, errors=errors, heteronym=heteronym, strict=strict,
- pinyin=py)
- if post_data is not None:
- py = post_data
- if not py:
- return []
- if isinstance(py, list):
- # 包含多音字信息
- if isinstance(py[0], list):
- if heteronym:
- return py
- # [[a, b], [c, d]]
- # [[a], [c]]
- return [[x[0]] for x in py]
- return [[i] for i in py]
- else:
- return [[py]]
- def post_handle_nopinyin(self, chars, style, heteronym,
- errors, strict,
- pinyin, **kwargs):
- """处理完没有拼音的字符串后会调用 ``post_handle_nopinyin`` 方法。
- 如果返回值不为 ``None`` 会使用返回的结果作为处理没有拼音的字符串的结果。
- :param chars: 待处理的没有拼音的字符串
- :param errors: 如何处理
- :param heteronym: 是否需要处理多音字
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :param pinyin: 处理后的拼音信息,值为空 list 或包含拼音信息的 list
- :param kwargs: 其他关键字参数,暂时无用,用于以后扩展新的参数。
- :return: ``None`` 或代替 ``pinyin`` 做为处理结果。
- """
- pass
- def post_pinyin(self, han, heteronym, pinyin, **kwargs):
- """找到汉字对应的拼音后,会调用 ``post_pinyin`` 方法。
- 如果返回值不为 ``None`` 会使用返回的结果作为 han 的拼音数据。
- :param han: 单个汉字或者词语
- :param heteronym: 是否需要处理多音字
- :param pinyin: 单个汉字的拼音数据或词语的拼音数据 list
- :type pinyin: list
- :param kwargs: 其他关键字参数,暂时无用,用于以后扩展新的参数。
- :return: ``None`` 或代替 ``pinyin`` 作为 han 的拼音 list。
- """
- pass
- def _phrase_pinyin(self, phrase, style, heteronym, errors, strict):
- """词语拼音转换.
- :param phrase: 词语
- :param errors: 指定如何处理没有拼音的字符
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :return: 拼音列表
- :rtype: list
- """
- pinyin_list = []
- if phrase in PHRASES_DICT:
- pinyin_list = deepcopy(PHRASES_DICT[phrase])
- else:
- for han in phrase:
- py = self._single_pinyin(han, style, heteronym, errors, strict)
- pinyin_list.extend(py)
- return pinyin_list
- def convert_styles(self, pinyin_list, phrase, style, heteronym, errors,
- strict, **kwargs):
- """转换多个汉字的拼音结果的风格"""
- for idx, item in enumerate(pinyin_list):
- han = phrase[idx]
- if heteronym:
- pinyin_list[idx] = [
- self.convert_style(
- han, orig_pinyin=x, style=style, strict=strict)
- for x in item
- ]
- else:
- orig_pinyin = item[0]
- pinyin_list[idx] = [
- self.convert_style(
- han, orig_pinyin=orig_pinyin, style=style,
- strict=strict)]
- return pinyin_list
- def _single_pinyin(self, han, style, heteronym, errors, strict):
- """单字拼音转换.
- :param han: 单个汉字
- :param errors: 指定如何处理没有拼音的字符,详情请参考
- :py:func:`~pypinyin.pinyin`
- :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
- 是否严格遵照《汉语拼音方案》来处理声母和韵母,
- 详见 :ref:`strict`
- :return: 返回拼音列表,多音字会有多个拼音项
- :rtype: list
- """
- num = ord(han)
- # 处理没有拼音的字符
- if num not in PINYIN_DICT:
- return self.handle_nopinyin(
- han, style=style, errors=errors,
- heteronym=heteronym, strict=strict)
- pys = PINYIN_DICT[num].split(',') # 字的拼音列表
- return [pys]
- def _convert_style(self, han, pinyin, style, strict, default,
- **kwargs):
- if not kwargs:
- kwargs = {}
- kwargs['han'] = han
- return convert_style(pinyin, style, strict, default=default, **kwargs)
- def _convert_nopinyin_chars(self, chars, style, heteronym, errors, strict):
- """转换没有拼音的字符。
- """
- if callable_check(errors):
- return errors(chars)
- if errors == 'default':
- return chars
- elif errors == 'ignore':
- return None
- elif errors == 'exception':
- raise PinyinNotFoundException(chars)
- elif errors == 'replace':
- if len(chars) > 1:
- return ''.join(text_type('%x' % ord(x)) for x in chars)
- else:
- return text_type('%x' % ord(chars))
- class _v2UConverter(V2UMixin, DefaultConverter):
- pass
- class _neutralToneWith5Converter(NeutralToneWith5Mixin, DefaultConverter):
- pass
- class _toneSandhiConverter(ToneSandhiMixin, DefaultConverter):
- pass
- class UltimateConverter(DefaultConverter):
- def __init__(self, v_to_u=False, neutral_tone_with_five=False,
- tone_sandhi=False, **kwargs):
- super(UltimateConverter, self).__init__(**kwargs)
- self._v_to_u = v_to_u
- self._neutral_tone_with_five = neutral_tone_with_five
- self._tone_sandhi = tone_sandhi
- def post_convert_style(self, han, orig_pinyin, converted_pinyin,
- style, strict, **kwargs):
- post_data = super(UltimateConverter, self).post_convert_style(
- han, orig_pinyin, converted_pinyin, style, strict, **kwargs)
- if post_data is not None:
- converted_pinyin = post_data
- if self._v_to_u:
- post_data = _v2UConverter().post_convert_style(
- han, orig_pinyin, converted_pinyin, style, strict, **kwargs)
- if post_data is not None:
- converted_pinyin = post_data
- if self._neutral_tone_with_five:
- post_data = _neutralToneWith5Converter().post_convert_style(
- han, orig_pinyin, converted_pinyin, style, strict, **kwargs)
- if post_data is not None:
- converted_pinyin = post_data
- return converted_pinyin
- def post_pinyin(self, han, heteronym, pinyin, **kwargs):
- post_data = super(UltimateConverter, self).post_pinyin(
- han, heteronym, pinyin, **kwargs)
- if post_data is not None:
- pinyin = post_data
- if self._tone_sandhi:
- post_data = _toneSandhiConverter().post_pinyin(
- han, heteronym, pinyin, **kwargs)
- if post_data is not None:
- pinyin = post_data
- return pinyin
- _mixConverter = UltimateConverter
|