用不到十句的脚本更正UTAU在中文系统下安装的乱码问题并将其转换为罗马音发音
使用方法
完整脚本如下,同时需要一个平假名和罗马音对应的数据表table
uta_patch.tar.gz
这是测试用的声库包
voice.tar.gz
使用方法是将voice解压到任意位置,将uta_patch的两个文件放在voice文件夹下,运行bash patch.sh
。
#!/bin/bash
# 获取日语原wav文件名列表
ls uta | grep -E "\.wav$" | iconv -f utf-8 -t cp936 | iconv -f cp932 -t utf-8 > jpname
# 乱码文件名列表
ls uta | grep -E "\.wav$" > errname
# 将错误文件名更正
paste errname jpname | awk '{print "mv uta/"$1" uta/"$2}' | bash
# 删除不用的文件
rm errname jpname
# 生成片假名和罗马音的对应表
# awk -F "[\"_]" '{print $2,$5}' rename.bat > table
# 将片假名文件名更改为罗马音文件名
awk '{print "mv uta/"$1".wav uta/"$2".wav"}' table | bash
awk '{print "mv uta/"$1"_wav.frq uta/"$2"_wav.frq"}' table | bash
# 将oto.ini以utf-8的格式复制成oto
iconv -f cp932 -t utf-8 uta/oto.ini > oto
# 准备更改oto文件的sed脚本
awk '{print "s/"$1"[,.]/"$2",/g"}' table > choto.sed
# 更改oto并送回去
sed -f choto.sed oto | sed 's/,/./' > uta/oto.ini
# 删除没用的文件
rm oto choto.sed
底层原理与语法分析
1、デフォルト出现乱码的原因
UTAU的默认声库在中文Windows系统安装会出现乱码的原因是安装器是以cp932编码写入文件名的,而桌面上的显示是文件名是cp936编码转换成UTF-8的显示。纯文本文件也是如此。
UTF-8是一种可以对应全球所有语言的字符编码,Windows纯文本在保存成文件之前都是以UTF-8传输数据的,保存时从UTF-8映射到本地的语言编码保存,读取时再通过对应编码转回到UTF-8查看。打个比方,如果是在日文系统下保存的文本,那么它的编码就是UTF-8到cp-932的映射,如果把它原封不动转移到中文系统下读取就会以UTF-8到cp-936的映射解读这个文本,出现的符号肯定是不对的。
解决这个问题用到了一个Linux下的工具iconv,它的基本语法是iconv -f from_codec -t to_codec filename
,也就是将一个文本文件从什么样的编码(-f)转换到什么样的编码(-t)。既然用cp936或者utf-8直接解读这个文件是错误的,那么-f后大部分时候跟的都应该是cp932,当然刻意制作乱码的文件名的时候除外。
2、vim
除了可以用iconv转换编码以外,还可以用vim查看和编辑不同编码的文件,其实vim底层就是用iconv转换编码的。
这里最重要的一个参数是fileencodings
,这个参数包括了vim在打开一个文件时会尝试的编码类型,如果打开的时候编码类型不对那么在编辑器里无论怎么改变fileencoding
或者encoding
都是不会得到正确的结果的。fileencoding
指这个文件的编码方式,也就是上面提到的文件储存在磁盘上的编码,encoding
指vim缓冲区、界面以及处理过程中使用的编码。
这三个参数的设置方法,fileencodings
应包含所有想要打开的文件的可能编码类型,这个程序的处理过程中就必须要包含cp036、cp932和utf-8。encoding
应该设置为UTF-8,因为桌面环境需要处理多语种。fileencoding
一般不需要手动设置,打开文件时会根据fileencodings
自动辨认,如果想要将文件储存为不同的编码的话可以改变后保存,比如将打开的cp932缓冲区中有意义的字符储存为utf-8来在终端直接输出可以在:set encoding=utf-8
以后:w
。
最后它们在~/.vimrc中应大致是这样的:
set fileencodings=cp932,cp936,utf-8,ucs-bom,latin1
# encoding默认就是utf-8,不用设置
3、grep
基本使用方法是grep pattern file
,一般都接在管道符后面省略文件名。pattern模板会隐式添加通配符,不需要做其他设置。
重要的是-E
参数,它可以让pattern指定一个正则表达式,最后就变成这样:grep -E "regex"
。-n
参数可以显示行号,-v
是反选(只输出不匹配的)。
4、sed
在这个脚本中主要用于替换操作,基本格式sed -f scriptfile filename
或者sed 's/pattern/totext/(g)'
,重点是-f
参数和替换命令s///
(最后一个斜杠一定不要掉)。
sed脚本后缀.sed
,不需要命令行中单引号以外的内容。
sed支持基本正则表达式(BRE)。
5、awk
在这个脚本中起到提取文本内容的作用,也用与将提取出的文本输出为sed脚本,非常重要。主要语句只有一句awk (-F "[splitters]") '{print ...}' filename
,可以在{}
包含的语句中用$0
表示整行内容,或者用$N
表示被分隔符隔开的第几个字段。
分隔符默认是任意空字符,可以用-F
参数指定,单个字符不需要"[]"
包络。/pattern/{}
前可以加上表达式过滤需要的行,也可以加上BEGIN{...}
和END{,,,}
来在读取流之前和处理完数据之后执行语句。
sed支持扩展正则表达式(ERE)。
6、paste
用于将两个文件以行的形式粘在一起,基本形式是paste file1 file2 ... outflie
。-d
参数可以指定分隔符,默认是tab。
脚本逐句分析
1、获取正常的日文文件名
ls uta | grep -E "\.wav$" | iconv -f utf-8 -t cp936 | iconv -f cp932 -t utf-8 > jpname
ls uta
将声库中的文件列出来送入grep进行过滤,过滤选项是后缀为.wav,这里的转义字符\
不可以省略,否则.
会被视为任意一个非空字符。iconv -f utf-8 -t cp936
获取wav文件的列表后用iconv
命令将数据流中的UTF-8字符(乱码的文件名)转换为cp936编码(cp932下正常的日文文件名,cp936下依然乱码),这一步重现了日文Windows下对文件名的写入。
用iconv
命令将cp936的数据流以cp932解码为UTF-8(UTF-8下正常的日文文件名,其他编码乱码),输出到jpname。
# jpname的输出应是这样的
あ.wav
い.wav
いぇ.wav
う.wav
うぃ.wav
うぇ.wav
うぉ.wav
...
2、获取中文系统下乱码的日文文件名
ls uta | grep -E "\.wav$" > errname
这一步没有需要解释的地方,直接以UTF-8的编码写入文件列表。
# errname的输出应是这样的
偁.wav
偄.wav
偄偉.wav
偆.wav
偆偂.wav
偆偉.wav
偆偋.wav
...
3、更改乱码的文件名至平假名文件名
paste errname jpname | awk '{print "mv uta/"$1" uta/"$2}' | bash
经过paste errname jpname
处理的数据流是这样的:
偁.wav あ.wav
...
经过awk '{print "mv uta/"$1" uta/"$2}'
处理的数据流是这样的:
mv uta/偁.wav uta/あ.wav
...
送入bash中进行处理。
*4、从renanme.bat转换罗马音与平假名的对应表(额外的步骤,table已经给出)
awk -F "[\"_]" '{print $2,$5}' rename.bat > table
rename.bat是这样的:
ren "あ_wav.frq" "a_wav_frq"
...
这里的awk语句"
和_
作为分隔符,平假名在第二个数据段,罗马音在第五个数据段,将它们之间加上空格隔开导出到table
。
# table的输出与应是这样,如果想要rename.bat的话可以在下面的文章界面下载
# http://kotkot.club/index.php/archives/440/
# 不过这里的rename.bat后来又做了一些修改,比如更正了发音和截去了前一部分文件,试试效果就好了
あ a
い i
いぇ ye
う u
うぃ whi
うぉ who
うぇ whe
...
5、将平假名文件名改为罗马音文件名
awk '{print "mv uta/"$1".wav uta/"$2".wav"}' table | bash
awk '{print "mv uta/"$1"_wav.frq uta/"$2"_wav.frq"}' table | bash
和3类似,处理结果如下图
6、将oto.ini转换为UTF-8编码便于后续处理
iconv -f cp932 -t utf-8 uta/oto.ini > oto
说白了就是把oto.ini在UTF-8下读出来的乱码还原成日文假名,因为现在只有从假名到罗马音的对应表,要经过一步中转。
7、根据table生成替代oto文本的sed脚本
awk '{print "s/"$1"[,.]/"$2",/g"}' table > choto.sed
awk处理出来的sed语句类似于这样:
s/あ[,.]/a,/g
s/い[,.]/i,/g
...
这里有一个问题,sed不支持零宽断言,所以为了匹配后面跟着.
或者,
的字符串只能把它们也一起带上,统一替换成,
,处理出来的oto文件wav前的点会变成逗号。后一步会把每行第一个错误的,
还原为.
。
8、处理oto并送回uta/oto.ini
sed -f choto.sed oto | sed 's/,/./' > uta/oto.ini
简单表示一下:
あ.wav=あ,6,52,69,0,0 ->
a,wav=a,6,52,69,0,0 ->
a.wav=a,6,52,69,0,0
9、完成
这样wav文件、frq文件和oto.ini的罗马音转换就全部完成了,再把它拖回uta的声库文件夹下就可以使用了,最后附上一张转换后的平假名与罗马音的对照表。
awk 'BEGIN{print "|hiragana|romaji|"; print "|--|--|"}{print "|"$1"|"$2"|"}' table > mdtable