core.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from __future__ import unicode_literals
  4. from itertools import chain
  5. from pypinyin.compat import text_type
  6. from pypinyin.constants import (
  7. PHRASES_DICT, PINYIN_DICT, Style, RE_HANS
  8. )
  9. from pypinyin.converter import DefaultConverter, UltimateConverter
  10. from pypinyin.contrib.tone_sandhi import ToneSandhiMixin
  11. from pypinyin.contrib.tone_convert import tone2_to_tone
  12. from pypinyin.seg import mmseg
  13. from pypinyin.seg.simpleseg import seg
  14. def load_single_dict(pinyin_dict, style='default'):
  15. """载入用户自定义的单字拼音库
  16. :param pinyin_dict: 单字拼音库。比如: ``{0x963F: u"ā,ē"}``
  17. :param style: pinyin_dict 参数值的拼音库风格. 支持 'default', 'tone2'
  18. :type pinyin_dict: dict
  19. """
  20. if style == 'tone2':
  21. for k, v in pinyin_dict.items():
  22. v = tone2_to_tone(v)
  23. PINYIN_DICT[k] = v
  24. else:
  25. PINYIN_DICT.update(pinyin_dict)
  26. mmseg.retrain(mmseg.seg)
  27. def load_phrases_dict(phrases_dict, style='default'):
  28. """载入用户自定义的词语拼音库
  29. :param phrases_dict: 词语拼音库。比如: ``{u"阿爸": [[u"ā"], [u"bà"]]}``
  30. :param style: phrases_dict 参数值的拼音库风格. 支持 'default', 'tone2'
  31. :type phrases_dict: dict
  32. """
  33. if style == 'tone2':
  34. for k, value in phrases_dict.items():
  35. v = [
  36. list(map(tone2_to_tone, pys))
  37. for pys in value
  38. ]
  39. PHRASES_DICT[k] = v
  40. else:
  41. PHRASES_DICT.update(phrases_dict)
  42. mmseg.retrain(mmseg.seg)
  43. class Pinyin(object):
  44. def __init__(self, converter=None, **kwargs):
  45. self._converter = converter or DefaultConverter()
  46. def pinyin(self, hans, style=Style.TONE, heteronym=False,
  47. errors='default', strict=True, **kwargs):
  48. """将汉字转换为拼音,返回汉字的拼音列表。
  49. :param hans: 汉字字符串( ``'你好吗'`` )或列表( ``['你好', '吗']`` ).
  50. 可以使用自己喜爱的分词模块对字符串进行分词处理,
  51. 只需将经过分词处理的字符串列表传进来就可以了。
  52. :type hans: unicode 字符串或字符串列表
  53. :param style: 指定拼音风格,默认是 :py:attr:`~pypinyin.Style.TONE` 风格。
  54. 更多拼音风格详见 :class:`~pypinyin.Style`
  55. :param errors: 指定如何处理没有拼音的字符。详见 :ref:`handle_no_pinyin`
  56. * ``'default'``: 保留原始字符
  57. * ``'ignore'``: 忽略该字符
  58. * ``'exception'``: 抛出异常
  59. :class:`~pypinyin.exceptions.PinyinNotFoundException`
  60. * ``'replace'``: 替换为去掉 ``\\u`` 的 unicode 编码字符串
  61. (``'\\u90aa'`` => ``'90aa'``)
  62. * callable 对象: 回调函数之类的可调用对象。
  63. :param heteronym: 是否启用多音字
  64. :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
  65. 是否严格遵照《汉语拼音方案》来处理声母和韵母,
  66. 详见 :ref:`strict`
  67. :return: 拼音列表
  68. :rtype: list
  69. """
  70. # 对字符串进行分词处理
  71. if isinstance(hans, text_type):
  72. han_list = self.seg(hans)
  73. else:
  74. if isinstance(self._converter, UltimateConverter) or \
  75. isinstance(self._converter, ToneSandhiMixin):
  76. han_list = []
  77. for h in hans:
  78. if not RE_HANS.match(h):
  79. han_list.extend(self.seg(h))
  80. else:
  81. han_list.append(h)
  82. else:
  83. han_list = chain(*(self.seg(x) for x in hans))
  84. pys = []
  85. for words in han_list:
  86. pys.extend(
  87. self._converter.convert(
  88. words, style, heteronym, errors, strict=strict))
  89. return pys
  90. def lazy_pinyin(self, hans, style=Style.NORMAL,
  91. errors='default', strict=True, **kwargs):
  92. """将汉字转换为拼音,返回不包含多音字结果的拼音列表.
  93. 与 :py:func:`~pypinyin.pinyin` 的区别是每个汉字的拼音是个字符串,
  94. 并且每个字只包含一个读音.
  95. :param hans: 汉字字符串( ``'你好吗'`` )或列表( ``['你好', '吗']`` ).
  96. 可以使用自己喜爱的分词模块对字符串进行分词处理,
  97. 只需将经过分词处理的字符串列表传进来就可以了。
  98. :type hans: unicode 字符串或字符串列表
  99. :param style: 指定拼音风格,默认是 :py:attr:`~pypinyin.Style.NORMAL` 风格。
  100. 更多拼音风格详见 :class:`~pypinyin.Style`。
  101. :param errors: 指定如何处理没有拼音的字符,详情请参考
  102. :py:func:`~pypinyin.pinyin`
  103. :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
  104. 是否严格遵照《汉语拼音方案》来处理声母和韵母,
  105. 详见 :ref:`strict`
  106. :return: 拼音列表(e.g. ``['zhong', 'guo', 'ren']``)
  107. :rtype: list
  108. """
  109. return list(
  110. chain(
  111. *self.pinyin(
  112. hans, style=style, heteronym=False,
  113. errors=errors, strict=strict)))
  114. def pre_seg(self, hans, **kwargs):
  115. """对字符串进行分词前将调用 ``pre_seg`` 方法对未分词的字符串做预处理。
  116. 默认原样返回传入的 ``hans``。
  117. 如果这个方法的返回值类型是 ``list``,表示返回的是一个分词后的结果,此时,
  118. ``seg`` 方法中将不再调用 ``seg_function`` 进行分词。
  119. :param hans: 分词前的字符串
  120. :return: ``None`` or ``list``
  121. """
  122. pass
  123. def seg(self, hans, **kwargs):
  124. """对汉字进行分词。
  125. 分词前会调用 ``pre_seg`` 方法,分词后会调用 ``post_seg`` 方法。
  126. :param hans:
  127. :return:
  128. """
  129. pre_data = self.pre_seg(hans)
  130. if isinstance(pre_data, list):
  131. seg_data = pre_data
  132. else:
  133. seg_data = self.get_seg()(hans)
  134. post_data = self.post_seg(hans, seg_data)
  135. if isinstance(post_data, list):
  136. return post_data
  137. return seg_data
  138. def get_seg(self, **kwargs):
  139. """获取分词函数。
  140. :return: 分词函数
  141. """
  142. return seg
  143. def post_seg(self, hans, seg_data, **kwargs):
  144. """对字符串进行分词后将调用 ``post_seg`` 方法对分词后的结果做处理。
  145. 默认原样返回传入的 ``seg_data``。
  146. 如果这个方法的返回值类型是 ``list``,表示对分词结果做了二次处理,此时,
  147. ``seg`` 方法将以这个返回的数据作为返回值。
  148. :param hans: 分词前的字符串
  149. :param seg_data: 分词后的结果
  150. :type seg_data: list
  151. :return: ``None`` or ``list``
  152. """
  153. pass
  154. _default_convert = DefaultConverter()
  155. _default_pinyin = Pinyin(_default_convert)
  156. def to_fixed(pinyin, style, strict=True):
  157. # 用于向后兼容,TODO: 废弃
  158. return _default_convert.convert_style(
  159. '', pinyin, style=style, strict=strict, default=pinyin)
  160. _to_fixed = to_fixed
  161. def handle_nopinyin(chars, errors='default', heteronym=True):
  162. # 用于向后兼容,TODO: 废弃
  163. return _default_convert.handle_nopinyin(
  164. chars, style=None, errors=errors, heteronym=heteronym, strict=True)
  165. def single_pinyin(han, style, heteronym, errors='default', strict=True):
  166. # 用于向后兼容,TODO: 废弃
  167. return _default_convert._single_pinyin(
  168. han, style, heteronym, errors=errors, strict=strict)
  169. def phrase_pinyin(phrase, style, heteronym, errors='default', strict=True):
  170. # 用于向后兼容,TODO: 废弃
  171. return _default_convert._phrase_pinyin(
  172. phrase, style, heteronym, errors=errors, strict=strict)
  173. def pinyin(hans, style=Style.TONE, heteronym=False,
  174. errors='default', strict=True,
  175. v_to_u=False, neutral_tone_with_five=False):
  176. """将汉字转换为拼音,返回汉字的拼音列表。
  177. :param hans: 汉字字符串( ``'你好吗'`` )或列表( ``['你好', '吗']`` ).
  178. 可以使用自己喜爱的分词模块对字符串进行分词处理,
  179. 只需将经过分词处理的字符串列表传进来就可以了。
  180. :type hans: unicode 字符串或字符串列表
  181. :param style: 指定拼音风格,默认是 :py:attr:`~pypinyin.Style.TONE` 风格。
  182. 更多拼音风格详见 :class:`~pypinyin.Style`
  183. :param errors: 指定如何处理没有拼音的字符。详见 :ref:`handle_no_pinyin`
  184. * ``'default'``: 保留原始字符
  185. * ``'ignore'``: 忽略该字符
  186. * ``'replace'``: 替换为去掉 ``\\u`` 的 unicode 编码字符串
  187. (``'\\u90aa'`` => ``'90aa'``)
  188. * callable 对象: 回调函数之类的可调用对象。
  189. :param heteronym: 是否启用多音字
  190. :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
  191. 是否严格遵照《汉语拼音方案》来处理声母和韵母,
  192. 详见 :ref:`strict`
  193. :param v_to_u: 无声调相关拼音风格下的结果是否使用 ``ü`` 代替原来的 ``v``
  194. 当为 False 时结果中将使用 ``v`` 表示 ``ü``
  195. :type v_to_u: bool
  196. :param neutral_tone_with_five: 声调使用数字表示的相关拼音风格下的结果是否
  197. 使用 5 标识轻声
  198. :type neutral_tone_with_five: bool
  199. :return: 拼音列表
  200. :rtype: list
  201. :raise AssertionError: 当传入的字符串不是 unicode 字符时会抛出这个异常
  202. Usage::
  203. >>> from pypinyin import pinyin, Style
  204. >>> import pypinyin
  205. >>> pinyin('中心')
  206. [['zhōng'], ['xīn']]
  207. >>> pinyin('中心', heteronym=True) # 启用多音字模式
  208. [['zhōng', 'zhòng'], ['xīn']]
  209. >>> pinyin('中心', style=Style.FIRST_LETTER) # 设置拼音风格
  210. [['z'], ['x']]
  211. >>> pinyin('中心', style=Style.TONE2)
  212. [['zho1ng'], ['xi1n']]
  213. >>> pinyin('中心', style=Style.CYRILLIC)
  214. [['чжун1'], ['синь1']]
  215. >>> pinyin('战略', v_to_u=True, style=Style.NORMAL)
  216. [['zhan'], ['lüe']]
  217. >>> pinyin('衣裳', style=Style.TONE3, neutral_tone_with_five=True)
  218. [['yi1'], ['shang5']]
  219. """
  220. _pinyin = Pinyin(UltimateConverter(
  221. v_to_u=v_to_u, neutral_tone_with_five=neutral_tone_with_five))
  222. return _pinyin.pinyin(
  223. hans, style=style, heteronym=heteronym, errors=errors, strict=strict)
  224. def slug(hans, style=Style.NORMAL, heteronym=False, separator='-',
  225. errors='default', strict=True):
  226. """将汉字转换为拼音,然后生成 slug 字符串.
  227. :param hans: 汉字字符串( ``'你好吗'`` )或列表( ``['你好', '吗']`` ).
  228. 可以使用自己喜爱的分词模块对字符串进行分词处理,
  229. 只需将经过分词处理的字符串列表传进来就可以了。
  230. :type hans: unicode 字符串或字符串列表
  231. :param style: 指定拼音风格,默认是 :py:attr:`~pypinyin.Style.NORMAL` 风格。
  232. 更多拼音风格详见 :class:`~pypinyin.Style`
  233. :param heteronym: 是否启用多音字
  234. :param separator: 两个拼音间的分隔符/连接符
  235. :param errors: 指定如何处理没有拼音的字符,详情请参考
  236. :py:func:`~pypinyin.pinyin`
  237. :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
  238. 是否严格遵照《汉语拼音方案》来处理声母和韵母,
  239. 详见 :ref:`strict`
  240. :return: slug 字符串.
  241. :raise AssertionError: 当传入的字符串不是 unicode 字符时会抛出这个异常
  242. ::
  243. >>> import pypinyin
  244. >>> from pypinyin import Style
  245. >>> pypinyin.slug('中国人')
  246. 'zhong-guo-ren'
  247. >>> pypinyin.slug('中国人', separator=' ')
  248. 'zhong guo ren'
  249. >>> pypinyin.slug('中国人', style=Style.FIRST_LETTER)
  250. 'z-g-r'
  251. >>> pypinyin.slug('中国人', style=Style.CYRILLIC)
  252. 'чжун1-го2-жэнь2'
  253. """
  254. return separator.join(
  255. chain(
  256. *_default_pinyin.pinyin(
  257. hans, style=style, heteronym=heteronym,
  258. errors=errors, strict=strict
  259. )
  260. )
  261. )
  262. def lazy_pinyin(hans, style=Style.NORMAL, errors='default', strict=True,
  263. v_to_u=False, neutral_tone_with_five=False, tone_sandhi=False):
  264. """将汉字转换为拼音,返回不包含多音字结果的拼音列表.
  265. 与 :py:func:`~pypinyin.pinyin` 的区别是返回的拼音是个字符串,
  266. 并且每个字只包含一个读音.
  267. :param hans: 汉字字符串( ``'你好吗'`` )或列表( ``['你好', '吗']`` ).
  268. 可以使用自己喜爱的分词模块对字符串进行分词处理,
  269. 只需将经过分词处理的字符串列表传进来就可以了。
  270. :type hans: unicode 字符串或字符串列表
  271. :param style: 指定拼音风格,默认是 :py:attr:`~pypinyin.Style.NORMAL` 风格。
  272. 更多拼音风格详见 :class:`~pypinyin.Style`。
  273. :param errors: 指定如何处理没有拼音的字符,详情请参考
  274. :py:func:`~pypinyin.pinyin`
  275. :param strict: 只获取声母或只获取韵母相关拼音风格的返回结果
  276. 是否严格遵照《汉语拼音方案》来处理声母和韵母,
  277. 详见 :ref:`strict`
  278. :param v_to_u: 无声调相关拼音风格下的结果是否使用 ``ü`` 代替原来的 ``v``
  279. 当为 False 时结果中将使用 ``v`` 表示 ``ü``
  280. :type v_to_u: bool
  281. :param neutral_tone_with_five: 声调使用数字表示的相关拼音风格下的结果是否
  282. 使用 5 标识轻声
  283. :type neutral_tone_with_five: bool
  284. :param tone_sandhi: 是否按照声调 `变调规则 <https://en.wikipedia.org/wiki/Standard_Chinese_phonology#Tone_sandhi>`__
  285. 对拼音进行处理
  286. (使用预先通过分词库进行过分词后的结果作为 ``hans``
  287. 参数的值效果会更好,因为变调效果依赖分词效果)
  288. :type tone_sandhi: bool
  289. :return: 拼音列表(e.g. ``['zhong', 'guo', 'ren']``)
  290. :rtype: list
  291. :raise AssertionError: 当传入的字符串不是 unicode 字符时会抛出这个异常
  292. Usage::
  293. >>> from pypinyin import lazy_pinyin, Style
  294. >>> import pypinyin
  295. >>> lazy_pinyin('中心')
  296. ['zhong', 'xin']
  297. >>> lazy_pinyin('中心', style=Style.TONE)
  298. ['zhōng', 'xīn']
  299. >>> lazy_pinyin('中心', style=Style.FIRST_LETTER)
  300. ['z', 'x']
  301. >>> lazy_pinyin('中心', style=Style.TONE2)
  302. ['zho1ng', 'xi1n']
  303. >>> lazy_pinyin('中心', style=Style.CYRILLIC)
  304. ['чжун1', 'синь1']
  305. >>> lazy_pinyin('战略', v_to_u=True)
  306. ['zhan', 'lüe']
  307. >>> lazy_pinyin('衣裳', style=Style.TONE3, neutral_tone_with_five=True)
  308. ['yi1', 'shang5']
  309. >>> lazy_pinyin('你好', style=Style.TONE2, tone_sandhi=True)
  310. ['ni2', 'ha3o']
  311. """ # noqa
  312. _pinyin = Pinyin(UltimateConverter(
  313. v_to_u=v_to_u, neutral_tone_with_five=neutral_tone_with_five,
  314. tone_sandhi=tone_sandhi))
  315. return _pinyin.lazy_pinyin(
  316. hans, style=style, errors=errors, strict=strict)