Преобразовать пронумерованный пиньинь в пиньинь с тональными метками - PullRequest
17 голосов
/ 20 ноября 2011

Существуют ли какие-либо скрипты, библиотеки или программы, использующие инструменты Python или BASH (например, awk, perl, sed), которые могут правильно преобразовывать пронумерованный пиньинь (например, dian4 nao3) в UTF-8 пиньинь с тональными метками (например, diàn nǎo)?

Я нашел следующие примеры, но они требуют PHP или #C:

У меня естьТакже найдены различные онлайн-инструменты, но они не могут обрабатывать большое количество конверсий.

Ответы [ 6 ]

19 голосов
/ 20 ноября 2011

У меня есть некоторый код Python 3, который делает это, и он достаточно мал, чтобы просто вставить сюда ответ прямо.* со всем, с чем я сталкивался.Для совместимости с Python 2 потребуются незначительные изменения.

5 голосов
/ 31 января 2014

Я написал еще одну функцию Python, которая делает это без учета регистра и сохраняет пробелы, знаки препинания и другой текст (если, конечно, нет ложных срабатываний):

# -*- coding: utf-8 -*-
import re

pinyinToneMarks = {
    u'a': u'āáǎà', u'e': u'ēéěè', u'i': u'īíǐì',
    u'o': u'ōóǒò', u'u': u'ūúǔù', u'ü': u'ǖǘǚǜ',
    u'A': u'ĀÁǍÀ', u'E': u'ĒÉĚÈ', u'I': u'ĪÍǏÌ',
    u'O': u'ŌÓǑÒ', u'U': u'ŪÚǓÙ', u'Ü': u'ǕǗǙǛ'
}

def convertPinyinCallback(m):
    tone=int(m.group(3))%5
    r=m.group(1).replace(u'v', u'ü').replace(u'V', u'Ü')
    # for multple vowels, use first one if it is a/e/o, otherwise use second one
    pos=0
    if len(r)>1 and not r[0] in 'aeoAEO':
        pos=1
    if tone != 0:
        r=r[0:pos]+pinyinToneMarks[r[pos]][tone-1]+r[pos+1:]
    return r+m.group(2)

def convertPinyin(s):
    return re.sub(ur'([aeiouüvÜ]{1,3})(n?g?r?)([012345])', convertPinyinCallback, s, flags=re.IGNORECASE)

print convertPinyin(u'Ni3 hao3 ma0?')
5 голосов
/ 21 мая 2012

Библиотека cjklib удовлетворяет ваши потребности:

Либо используйте оболочку Python:

>>> from cjklib.reading import ReadingFactory
>>> f = ReadingFactory()
>>> print f.convert('Bei3jing1', 'Pinyin', 'Pinyin', sourceOptions={'toneMarkType': 'numbers'})
Běijīng

Или просто командная строка:

$ cjknife -m Bei3jing1
Běijīng

Отказ от ответственности: я разработал эту библиотеку.

1 голос
/ 12 июня 2019

Я перенес код Kotlin @ Lakedaemon на Java.

// auxiliary function
static public String getCharacter(String string, int position) {
    char[] characters = string.toCharArray();
    return String.valueOf(characters[position]);
}

static public String toPinyin(String asciiPinyin) {
    Map<String, String> pinyinToneMarks = new HashMap<String, String>();
    pinyinToneMarks.put("a", "āáǎà"); pinyinToneMarks.put("e", "ēéěè");
    pinyinToneMarks.put("i", "īíǐì"); pinyinToneMarks.put("o",  "ōóǒò");
    pinyinToneMarks.put("u", "ūúǔù"); pinyinToneMarks.put("ü", "ǖǘǚǜ");
    pinyinToneMarks.put("A",  "ĀÁǍÀ"); pinyinToneMarks.put("E", "ĒÉĚÈ");
    pinyinToneMarks.put("I", "ĪÍǏÌ"); pinyinToneMarks.put("O", "ŌÓǑÒ");
    pinyinToneMarks.put("U", "ŪÚǓÙ"); pinyinToneMarks.put("Ü",  "ǕǗǙǛ");

    Pattern pattern = Pattern.compile("([aeiouüvÜ]{1,3})(n?g?r?)([012345])");
    Matcher matcher = pattern.matcher(asciiPinyin);
    StringBuilder s = new StringBuilder();
    int start = 0;
    while (matcher.find(start)) {
        s.append(asciiPinyin, start, matcher.start(1));
        int tone = Integer.parseInt(matcher.group(3)) % 5;
        String r = matcher.group(1).replace("v", "ü").replace("V", "Ü");
        // for multple vowels, use first one if it is a/e/o, otherwise use second one
        int pos = r.length() > 1 && "aeoAEO".contains(getCharacter(r,0).toString())? 1 : 0;
        if (tone != 0) {
            s.append(r, 0, pos).append(getCharacter(pinyinToneMarks.get(getCharacter(r, pos)),tone - 1)).append(r, pos + 1, r.length());
        } else {
            s.append(r);
        }
        s.append(matcher.group(2));
        start = matcher.end(3);
    }
    if (start != asciiPinyin.length()) {
        s.append(asciiPinyin, start, asciiPinyin.length());
    }
    return s.toString();
}
1 голос
/ 10 октября 2014

Я перенес код из dani_l в Kotlin (код в java должен быть очень похожим). Идет:

import java.util.regex.Pattern
val pinyinToneMarks = mapOf(
    'a' to "āáǎà",
    'e' to "ēéěè",
    'i' to "īíǐì",
    'o' to  "ōóǒò",
    'u' to "ūúǔù",
    'ü' to "ǖǘǚǜ",
    'A' to  "ĀÁǍÀ",
    'E' to "ĒÉĚÈ",
    'I' to "ĪÍǏÌ",
    'O' to "ŌÓǑÒ",
    'U' to "ŪÚǓÙ",
    'Ü' to  "ǕǗǙǛ"
)

fun toPinyin(asciiPinyin: String) :String {
  val pattern = Pattern.compile("([aeiouüvÜ]{1,3})(n?g?r?)([012345])")!!
  val matcher = pattern.matcher(asciiPinyin)
  val s = StringBuilder()
  var start = 0
  while (matcher.find(start)) {
      s.append(asciiPinyin, start, matcher.start(1))
      val tone = Integer.parseInt(matcher.group(3)!!) % 5
      val r = matcher.group(1)!!.replace("v", "ü").replace("V", "Ü")
      // for multple vowels, use first one if it is a/e/o, otherwise use second one
      val pos = if (r.length >1 && r[0].toString() !in "aeoAEO") 1 else 0
      if (tone != 0) s.append(r, 0, pos).append(pinyinToneMarks[r[pos]]!![tone - 1]).append(r, pos + 1, r.length)
      else s.append(r)
      s.append(matcher.group(2))
      start = matcher.end(3)
  }
  if (start != asciiPinyin.length) s.append(asciiPinyin, start, asciiPinyin.length)
  return s.toString()
}

fun test() = print(toPinyin("Ni3 hao3 ma0?"))
0 голосов
/ 22 января 2014

Я столкнулся с макросом VBA, который делает это в Microsoft Word, по адресу pinyinjoe.com

У меня был небольшой недостаток, о котором я сообщил, и он ответил, что включит мое предложение "как только смогу »Это было в начале января 2014 года;У меня не было никакой мотивации для проверки, так как это уже сделано в моей копии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...