我有一组来自Windows的SHIFT_JIS(日文)编码的csv文件,我试图在运行Perl v5.10.1的Linux服务器上使用正则表达式来处理字符串替换。
这是我的要求: 我希望Perl脚本的正则表达式是人类可读的(至少对日本人来说) IE浏览器。像这样: S /北/ 0 /克; 而不是它散落着一些十六进制代码 S / \ X {4eba} / 0 /克;
现在,我正在Windows上的Notepad ++中编辑Perl脚本,并将我需要搜索的字符串从csv数据文件粘贴到Perl脚本上。
我在下面有以下工作测试脚本:
use strict;
use warnings;
use utf8;
open (IN1, "<:encoding(shift_jis)", "${work_dir}/tmp00.csv") or die "Error: tmp00.csv\n";
open (OUT1, "+>:encoding(shift_jis)" , "${work_dir}/tmp01.csv") or die "Error: tmp01.csv\n";
while (<IN1>)
{
print $_ . "\n";
chomp;
s/北/0/g;
s/10:00/9:00/g;
print OUT1 "$_\n";
}
close IN1;
close OUT1;
这将成功替换csv文件中9:00的10:00,但问题是我无法用0代替北(即。),除非使用utf8也包含在顶部。
问题:
1)在开放文档http://perldoc.perl.org/functions/open.html中,我没有看到使用utf8作为要求,除非它是隐含的?
a)如果我只使用utf8,那么循环中的第一个print语句会将垃圾字符打印到我的xterm屏幕。
b)如果我只使用:encoding(shift_jis)调用open,那么循环中的第一个print语句会将日文字符打印到我的xterm屏幕,但不会发生替换。没有指出使用utf8的警告。
c)如果我同时使用a)和b),则此示例有效。
在这个Perl脚本中,“使用utf8”如何修改调用open的行为:enoding(shift_jis)?
2)我也尝试在没有指定任何编码的情况下打开文件,Perl不会将文件字符串视为原始字节,并且如果我粘贴在脚本中的字符串是,则能够以这种方式执行正则表达式匹配与原始数据文件中的文本编码相同?我之前能够以这种方式更换文件名,而无需指定任何编码(请参阅我的相关帖子:Perl Japanese to English filename replacement)。
感谢。
更新1
在Perl中测试一个简单的本地化示例,用于替换日语中的文件名和文件文本
在Windows XP中,从.csv数据文件中复制南字符并复制到剪贴板,然后将其用作文件名(即南.txt)和文件内容(南)。在Notepad ++中,在UTF-8编码下读取文件显示x93xEC,在SHIFT_JIS下读取它显示南。
脚本:
使用以下Perl脚本south.pl,它将在具有Perl 5.10的Linux服务器上运行
#!/usr/bin/perl
use feature qw(say);
use strict;
use warnings;
use utf8;
use Encode qw(decode encode);
my $user_dir="/usr/frank";
my $work_dir = "${user_dir}/test_south";
# forward declare the function prototypes
sub fileProcess;
opendir(DIR, ${work_dir}) or die "Cannot open directory " . ${work_dir};
# readdir OPTION 1 - shift_jis
#my @files = map { Encode::decode("shift_jis", $_); } readdir DIR; # Note filename could not be decoded as shift_jis
#binmode(STDOUT,":encoding(shift_jis)");
# readdir OPTION 2 - utf8
my @files = map { Encode::decode("utf8", $_); } readdir DIR; # Note filename could be decoded as utf8
binmode(STDOUT,":encoding(utf8)"); # setting display to output utf8
say @files;
# pass an array reference of files that will be modified
fileNameTranslate();
fileProcess();
closedir(DIR);
exit;
sub fileNameTranslate
{
foreach (@files)
{
my $original_file = $_;
#print "original_file: " . "$original_file" . "\n";
s/南/south/;
my $new_file = $_;
# print "new_file: " . "$_" . "\n";
if ($new_file ne $original_file)
{
print "Rename " . $original_file . " to \n\t" . $new_file . "\n";
rename("${work_dir}/${original_file}", "${work_dir}/${new_file}") or print "Warning: rename failed because: $!\n";
}
}
}
sub fileProcess
{
# file process OPTION 3, open file as shift_jis, the search and replace would work
# open (IN1, "<:encoding(shift_jis)", "${work_dir}/south.txt") or die "Error: south.txt\n";
# open (OUT1, "+>:encoding(shift_jis)" , "${work_dir}/south1.txt") or die "Error: south1.txt\n";
# file process OPTION 4, open file as utf8, the search and replace would not work
open (IN1, "<:encoding(utf8)", "${work_dir}/south.txt") or die "Error: south.txt\n";
open (OUT1, "+>:encoding(utf8)" , "${work_dir}/south1.txt") or die "Error: south1.txt\n";
while (<IN1>)
{
print $_ . "\n";
chomp;
s/南/south/g;
print OUT1 "$_\n";
}
close IN1;
close OUT1;
}
结果:
(BAD)取消评估选项1和3,(评论选项2和4) 设置:Readdir编码,SHIFT_JIS;文件打开编码SHIFT_JIS 结果:文件名替换失败.. 错误:utf8“\ x93”未映射到.//south.pl第68行的Unicode。 \ X93
(BAD)取消评估选项2和4(评论选项1和3) 设置:Readdir编码,utf8;文件打开编码utf8 结果:文件名替换工作,生成了south.txt 但是south1.txt文件内容替换失败,它有内容\ x93()。 错误:“\ x {fffd}”没有映射到.//south.pl第25行的shiftjis。 ...... -Ao?=(Bx {fffd} .txt
(GOOD)取消评估选项2和3,(评论选项1和4) 设置:Readdir编码,utf8;文件打开编码SHIFT_JIS 结果:文件名替换工作,生成了south.txt South1.txt文件内容替换有效,它有内容南。
结论:
我必须使用不同的编码方案才能正常工作。 Readdir utf8和文件处理SHIFT_JIS,因为csv文件的内容是SHIFT_JIS编码的。
答案 0 :(得分:1)
一个好的开始就是阅读the documentation for the utf8 module。其中说:
use utf8
pragma告诉Perl解析器允许使用UTF-8 当前词法范围内的程序文本(允许EBCDIC上的UTF-EBCDIC) 基于平台)。no utf8
编译指示告诉Perl切换回 将源文本视为当前词法中的文字字节 范围。
如果您的代码中没有use utf8
,那么Perl编译器会假定您的源代码采用系统的本机单字节编码。角色'北'没什么意义。添加pragma告诉Perl你的代码包含Unicode字符,一切都开始工作。