是否有使用Python
或BASH
工具(例如awk
、perl
、sed
)的脚本、库或程序可以正确地将数字拼音(例如dian4 nao3)转换为带声调标记的UTF-8拼音(例如diàn nǎo)?
我找到了以下示例,但它们需要使用PHP或C#:
- [PHP] 将数字拼音转换为带声调标记的拼音?
- [C#] 有没有库可以将数字拼音转换为带声调标记的拼音?
我还发现了各种在线工具,但它们无法处理大量的转换。
是否有使用Python
或BASH
工具(例如awk
、perl
、sed
)的脚本、库或程序可以正确地将数字拼音(例如dian4 nao3)转换为带声调标记的UTF-8拼音(例如diàn nǎo)?
我找到了以下示例,但它们需要使用PHP或C#:
我还发现了各种在线工具,但它们无法处理大量的转换。
PinyinToneMark = {
0: "aoeiuv\u00fc",
1: "\u0101\u014d\u0113\u012b\u016b\u01d6\u01d6",
2: "\u00e1\u00f3\u00e9\u00ed\u00fa\u01d8\u01d8",
3: "\u01ce\u01d2\u011b\u01d0\u01d4\u01da\u01da",
4: "\u00e0\u00f2\u00e8\u00ec\u00f9\u01dc\u01dc",
}
def decode_pinyin(s):
s = s.lower()
r = ""
t = ""
for c in s:
if c >= 'a' and c <= 'z':
t += c
elif c == ':':
assert t[-1] == 'u'
t = t[:-1] + "\u00fc"
else:
if c >= '0' and c <= '5':
tone = int(c) % 5
if tone != 0:
m = re.search("[aoeiuv\u00fc]+", t)
if m is None:
t += c
elif len(m.group(0)) == 1:
t = t[:m.start(0)] + PinyinToneMark[tone][PinyinToneMark[0].index(m.group(0))] + t[m.end(0):]
else:
if 'a' in t:
t = t.replace("a", PinyinToneMark[tone][0])
elif 'o' in t:
t = t.replace("o", PinyinToneMark[tone][1])
elif 'e' in t:
t = t.replace("e", PinyinToneMark[tone][2])
elif t.endswith("ui"):
t = t.replace("i", PinyinToneMark[tone][3])
elif t.endswith("iu"):
t = t.replace("u", PinyinToneMark[tone][4])
else:
t += "!"
r += t
t = ""
r += t
return r
这个函数处理我遇到的所有字符,包括ü
,u:
和v
。为了兼容Python 2,需要进行一些小的修改。
# -*- 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?')
cjklib库 可以满足您的需求:
您可以使用Python shell:
>>> 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
$ cjknife.py -m "ni3hao3吗?Hello"
将返回 "nǐhǎo吗?Hello"。然而,如果您输入的是"How are you?",它会抱怨缺少 "you" 这个带声调的音节,因为它是一个有效的拼音音节。所以我想您需要先将英语和拼音分开处理。 - cburgmer更新的代码: 请注意,@Lakedaemon的Kotlin代码没有考虑声调位置规则。
我最初将@Lakedaemon的Kotlin代码移植到Java,现在我已经修改了代码并敦促使用此代码或@Lakedaemon的Kotlin代码的人更新代码。
我添加了一个额外的辅助函数来获取正确的声调标记位置。
private static int getTonePosition(String r) {
String lowerCase = r.toLowerCase();
// exception to the rule
if (lowerCase.equals("ou")) return 0;
// higher precedence, both never go together
int preferencePosition = lowerCase.indexOf('a');
if (preferencePosition >= 0) return preferencePosition;
preferencePosition = lowerCase.indexOf('e');
if (preferencePosition >= 0) return preferencePosition;
// otherwise the last one takes the tone mark
return lowerCase.length() - 1;
}
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<>();
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", "Ü");
if (tone != 0) {
int pos = getTonePosition(r);
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();
}
getCharacter()
方法中为什么不使用string.charAt(position)
? - Thomaspip install dragonmapper
),可以将汉字转换为拼音。
from dragonmapper.transcriptions import hanzi
hanzi.to_pinyin("过河拆桥。")
# >>> 'guòhéchāiqiáo。'
hanzi.to_pinyin("过河拆桥。", accented=False)
# >>> 'guo4he2chai1qiao2。'
from dragonmapper.transcriptions import accented_to_numbered
accented_to_numbered('guò hé chāi qiáo。')
# >>> 'guo4 he2 chai1 qiao2。'
from dragonmapper.transcriptions import numbered_to_accented
numbered_to_accented('guo4 he2 chai1 qiao2。')
# >>> 'guò hé chāi qiáo。'
免责声明:本人与dragonmapper作者无任何关系
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?"))
我发现了一个在Microsoft Word中实现的VBA宏,网址是pinyinjoe.com
它有一个小缺陷,我向作者报告后他回应说他会尽快将我的建议纳入到宏中。那是在2014年1月初; 由于这个功能已经在我的副本中完成了,所以我没有再去验证这个宏。
decode_pinyin
是一个函数。可以像这样调用它:decode_pinyin("ni3 hao3")
,或者从文件中读取输入,或者使用其他你喜欢的方式。 - Greg Hewgill\u...
字符的字符串前面添加一个u
(表示Unicode),这为我解决了问题。 - Herman Schaaf