需求
此前项目中有一个中文转拼音的需求,于是整理了一下实现方法。
在转换过程中,这里我保留了数字和字母,其他特殊字符或者空格将会被去掉。如
测试
会被转换成CeShi
。(可自行修改convert2Pinyin()
方法实现其他需求)
实现
话不多说(Github Demo)
<!-- html -->
<input id="input" value="测试" />
<input id="output" disabled />
// js
window.onload = () => {
const input = document.getElementById('input')
const output = document.getElementById('output')
// 失焦进行转换
input.addEventListener('blur', () => {
const val = input.value
output.value = convertToPinyin(val)
})
/**
* 转换成拼音(若有空格、特殊字符将被移除)
*
* @param {string} sourceStr 原始数据
*/
const convertToPinyin = sourceStr => {
// 目标数据
let targetStr = ''
// 匹配中文
const cnReg = /[\u4e00-\u9fa5]/
// 匹配数字和英文
const enReg = /[a-zA-Z0-9]/
// 保留英文和数字
const keep = true
// 遍历源数据
for (let i = 0, len = sourceStr.length; i < len; i++) {
const str = sourceStr.substr(i, 1)
if (keep && enReg.test(str)) {
targetStr += str
} else if (cnReg.test(str)) {
const searchResult = searchPinYin(str, PinYin)
if (searchResult) {
// targetStr += searchResult
targetStr += capitalize(searchResult) // 首字母大写
}
}
}
return targetStr
}
/**
* 检索拼音
*
* @param {string} str 源字符串
* @param {object} data 收集的拼音 Unicode 编码集合
*/
const searchPinYin = (str, data) => {
for (const key in data) {
if (data.hasOwnProperty(key) && data[key].indexOf(str) !== -1) {
return key
}
}
return ''
}
/**
* 将拼音首字母转换为大写
*
* @param {string} str 源字符串
*/
const capitalize = str => {
if (str) {
const [first] = str
const other = str.replace(/^\S/, '')
return `${first.toUpperCase()}${other}`
}
return str
}
/**
* 目前这个 16 进制 Unicode 编码是网上收集的,可能不能覆盖所有的中文字符,可以自行补充;
*
* 例如:‘婋’(xiao)字:
* 1、使用 '婋'.charCodeAt(0).toString(16) 得到 Unicode 编码:5a4b;
* 2、将编码前面加上:\u => \u5a4b;
* 3、然后放到对象 PinYin['xiao'] 里面。
*
* 现在只想到了这种笨方法一个一个往里补充,如果有更好的方法,欢迎指出!!!
*/
const PinYin = {
a: '\u554a\u963f\u9515'
// ...
// 由于这块代码太多,这里省略就不贴上来了,麻烦请看 GitHub Demo。
}
}
难点
其实在中文转拼音的过程中,比较麻烦的在于多音字
和生僻字
的实现,我想到的解决思路是:
生僻字:是由于
PinYin
里面列举的缺失一些中文字符,可通过str.charCodeAt(0).toString(16)
的方式补充,具体方法不再赘述,上面有说明。多音字:其实多音字一直是最麻烦的地方,因为每一个中文字符只有一个对应的 Unicode 编码,所以需要在对象的多个对应属性上添加编码。
如曾
字,通过'曾'.charCodeAt(0).toString(16)
获取到66fe
,然后前面拼接上\u
,得到\u66fe
。
// 截取 PinYin 一小部分
const PinYin = {
ceng: '\u66fe',
zeng: '\u66fe'
}
然后修改上述 convert2Pinyin()
和 searchPinYin()
方法,把符合规则的字符返回一个数组,然后用排列组合的方式列出所有可能。