0

我有一组来自 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 编码的。

4

1 回答 1

1

一个好的起点是阅读utf8 模块的文档。其中说:

pragma 告诉 Perl 解析器在use utf8当前词法范围内的程序文本中允许 UTF-8(在基于 EBCDIC 的平台上允许 UTF-EBCDIC)。no utf8pragma 告诉 Perl 切换回将源文本视为当前词法范围内的文字字节。

如果您use utf8的代码中没有,则 Perl 编译器假定您的源代码采用系统的本机单字节编码。而“北”这个字符将毫无意义。添加 pragma 告诉 Perl 你的代码包含 Unicode 字符并且一切都开始工作了。

于 2013-06-12T16:01:23.190 回答