我有一组来自 Windows 的 SHIFT_JIS(日语)编码的 csv 文件,我试图在运行 Perl v5.10.1 的 Linux 服务器上使用正则表达式进行字符串替换。
这是我的要求:我希望 Perl 脚本的正则表达式是人类可读的(至少对日本人来说)即。像这样:s/北/0/g;取而代之的是一些十六进制代码 s/\x{4eba}/0/g;
现在,我正在 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 文件中的 10:00 替换为 9:00,但问题是我无法用 0 替换北(即北),除非顶部还包含使用 utf8。
问题:
1)在开放文档http://perldoc.perl.org/functions/open.html中,我没有看到使用 utf8 作为要求,除非它是隐式的?
a) 如果我只使用 utf8,那么循环中的第一个打印语句会将垃圾字符打印到我的 xterm 屏幕上。
b) 如果我只用 :encoding(shift_jis) 调用 open,那么循环中的第一个 print 语句会将日语字符打印到我的 xterm 屏幕,但不会发生替换。没有未指定使用 utf8 的警告。
c) 如果我同时使用了 a) 和 b),那么这个例子可以工作。
在这个 Perl 脚本中,“使用 utf8”如何修改使用 :enoding(shift_jis) 调用 open 的行为?
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
(坏)取消注释选项 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 编码的。