这是我的计划
#!/bin/perl use strict; use warnings; use open ':std'; use open ':encoding(UTF-8)'; use Encode qw( encode decode ); use Data::Dump qw(dump); use Getopt::Long qw(GetOptions); Getopt::Long::Configure qw(gnu_getopt); my $font; my %map; GetOptions( 'font|f=s' => \$font,'help|h' => \&usage,) or die "Try $0 -h for help"; print "Do you want to map $font? (y/n)"; chomp( my $answer = lc <STDIN> ); $font = lc( $font ); $font =~ s/ /_/; $font =~ s/(.*?)\.ttf/$1/; if ( $answer eq "y" ) { map_font(); } else { restore_map(); } foreach ( @ARGV ) { my $modfile = "$_"; $modfile =~ s/.*\/(.*)/uni$1/; process_file( $_,$modfile ); } sub process_file { my @options = @_; open my $source,'<',"$options[0]"; my $result = $options[1]; my $test = "./text"; my $missingchar = join( "|",map( quoteMeta,sort { length $b <=> length $a } keys %map ) ); while ( <$source> ) { $/ = undef; s/h;/u;/g; #Might need change based on the tamil font s/N(.)/$1N/g; #Might need change based on the tamil font s/n(.)/$1n/g; #Might need change based on the font s/($missingchar)/$map{$1}/g; print "$_"; open my $final,'>:utf8',"$result"; print $final "$_"; close $final; } } sub map_font { my @oddhexes = qw/0B95 0B99 0B9A 0B9E 0B9F 0BA3 0BA4 0BA8 0BAA 0BAE 0BAF 0BB0 0BB2 0BB5 0BB3 0BB4 0BB1 0BA9/; my @missingletters = qw/0BC1 0BC2/; my @rest = qw/0B85 0B86 0B87 0B88 0B89 0B8A 0B8E 0B8F 0B90 0B92 0B93 0B83 0BBE 0BBF 0BC0 0BC6 0BC7 0BC8 0BCD 0B9C 0BB7 0BB8 0BB9 0BCB 0BCA 0BCC/; foreach ( @oddhexes ) { my $oddhex = $_; $_ = encode( 'utf8',chr( hex( $_ ) ) ); print "Press the key for $_ :"; chomp( my $bole = <STDIN> ); if ( $bole eq "" ) { next; } $map{$bole} = $_; foreach ( @missingletters ) { my $oddchar = encode( 'utf8',chr( hex( $oddhex ) ) . chr( hex( $_ ) ) ); print "Press the key for $oddchar :"; chomp( my $missingchar = <STDIN> ); if ( $missingchar eq "" ) { next } $map{$missingchar} = $oddchar; } } foreach ( @rest ) { $_ = encode( 'utf8',chr( hex( $_ ) ) ); print "Press the key for $_ :"; chomp( my $misc = <STDIN> ); if ( $misc eq "" ) { next } $map{$misc} = $_; } open my $OUTPUT,'>',$font || die "can't open file"; print $OUTPUT dump( \%map ); close $OUTPUT; } sub restore_map { open my $in,"$font" || die "can't open file: $!"; { local $/; %map = %{ eval <$in> }; } close $in; } sub usage { print "\nUsage: $0 [options] {file1.txt file2.txt..} \neg: $0 -f TamilBible.ttf chapter.txt\n\nOptions:\n -f --font - used to pass font name\n -h --help - Prints help\n\nManual mapping of font is essential for using this program\n"; exit; }
在子程序process_file中,输出print“$_”;在terminal中显示正确的泰米尔语Unicode字符.
然而output to the file handle $决赛是非常不同的.
%map是here.
为什么输出不同?
我该如何纠正这种行为?
解决方法
open my $final,"$result";
将文件句柄设置为期望字符,然后在出路时编码为UTF-8序列.但是你从%map hash发送预编码的字节序列,这会导致这些字节被视为字符并由Perl IO再次编码
相比之下,你的终端被设置为期望UTF-8编码的数据,但STDOUT根本没有设置为任何编码(使用open’:std’对它自己没有影响,见下文)所以它通过你的UTF -8编码的字节通过不变,恰好是终端期望的
顺便说一句,您已为输入和输出流设置了默认的打开模式:encoding(UTF-8)
use open ':encoding(UTF-8)'
但是在打开电话时已经覆盖了它. :utf8模式从宽字符到字节序列进行了非常基本的转换,但是:编码(UTF-8)更有用,因为它检查每个正在打印的字符是否是有效的Unicode值.很有可能它会遇到这样的错误,最好是允许默认并且只写
open my $final,$result;
为了保持干净整洁,您的程序应该以字符形式工作,并且文件句柄应设置为在打印这些字符时将这些字符编码为UTF-8
您可以通过添加将UTF-8设置为所有新打开的文件句柄以及STDIN和STDOUT的默认编码
use open qw/ :std :encoding(utf-8) /;
到你的程序的顶部(:encoding(utf-8)比:utf8更好)并删除所有要编码的调用.你几乎没有,但是:std和:encoding(utf-8)需要在同一个use语句中
你还应该添加
use utf8;
在最顶层,以便您可以在程序本身中使用UTF-8字符
您还有一些偶然的错误.例如
>在声明中
open my $in,"$font" || die "can't open file: $!";
引用像$font这样的单个标量变量几乎总是错误的,除非它碰巧是一个对象并且你想要调用stringification方法
你需要或代替||,否则你只是测试$font的真相
如果我问你一个名为$in的变量可能包含什么,我想你会犹豫不决; $in_fh更好,是一个常见的习语
将文件名放入die字符串以及$的原因总是很好!
考虑到所有这些因素使您的陈述看起来像这样
open my $in_fh,$font or die qq{Unable to open "$font" for input: $!};
>你应该在大写和小写标量变量之间保持一致,小写是正确的选择.所以
open my $OUTPUT,$font || die "can't open file";
应该是这样的
open my $out_fh,$font or die qq{Unable to open "$font" for output: $!};
>这条线
$/ = undef;
你应该在其他地方使用本地$/,否则你将永久修改其余程序和模块的输入记录分隔符.它也会在第一次从文件句柄读取后出现,因此您的程序将读取并处理一行,然后在while循环的下一次迭代中处理整个文件的其余部分