One*_*ace 6 unicode perl utf-8
我正在编写一个Perl程序,将我的本地语言ASCII字符转换为Unicode字符(泰米尔语).
这是我的计划
#!/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;
}
Run Code Online (Sandbox Code Playgroud)
在子程序中process_file,输出print "$_";在终端显示正确的泰米尔语Unicode字符.
的%map是在这里.
为什么输出不同?
我该如何纠正这种行为?
我看过这个问题,但这不一样.在我的情况下,终端显示正确的结果,而文件句柄输出是不同的.
你的公开声明
open my $final, '>:utf8', "$result";
Run Code Online (Sandbox Code Playgroud)
将文件句柄设置为期望字符,然后在出路时编码为UTF-8序列.但是您从%map散列中发送预编码的字节序列,这会导致这些字节被视为字符并由Perl IO 再次编码
相比之下,你的终端被设置为期望UTF-8编码的数据,但是STDOUT根本没有设置为任何编码(use open ':std'对它自己没有影响,见下文)所以它通过你的UTF-8编码的字节不变这恰好是终端所期望的
顺便说一句,您已:encoding(UTF-8)为输入和输出流设置了默认的打开模式
use open ':encoding(UTF-8)'
Run Code Online (Sandbox Code Playgroud)
但是在你的电话中已经覆盖了它open.该:utf8模式从宽字符到字节序列进行了非常基本的转换,但:encoding(UTF-8)更有用,因为它检查每个正在打印的字符是否是有效的Unicode值.很有可能它会遇到这样的错误,最好是允许默认并且只写
open my $final, '>', $result;
Run Code Online (Sandbox Code Playgroud)
为了保持干净整洁,您的程序应该以字符形式工作,并且文件句柄应设置为在打印这些字符时将这些字符编码为UTF-8
您可以设置UTF-8作为所有新打开的文件的默认编码处理以及STDIN和STDOUT加入
use open qw/ :std :encoding(utf-8) /;
Run Code Online (Sandbox Code Playgroud)
到程序的顶部(:encoding(utf-8)最好是:utf8)并删除所有的调用encode.你有它差不多吧,但是:std并:encoding(utf-8)需要在同一use声明
你还应该添加
use utf8;
Run Code Online (Sandbox Code Playgroud)
在最顶层,以便您可以在程序本身中使用UTF-8字符
您还有一些偶然的错误.例如
在声明中
open my $in, '<', "$font" || die "can't open file: $!";
Run Code Online (Sandbox Code Playgroud)
引用单个标量变量几乎总是错误的,$font除非它碰巧是一个对象并且你想调用字符串化方法
你需要or代替||,否则你只是在测试真相$font
如果我问你所谓的变量是什么,$in我认为你会犹豫不决; $in_fh更好,是一个常见的习语
我总是很高兴把名字的文件到die字符串还有理由从$!
考虑到所有这些因素使您的陈述看起来像这样
open my $in_fh, '<', $font or die qq{Unable to open "$font" for input: $!};
Run Code Online (Sandbox Code Playgroud)您应该在大写和小写标量变量之间保持一致,小写是正确的选择.所以
open my $OUTPUT, '>', $font || die "can't open file";
Run Code Online (Sandbox Code Playgroud)
应该是这样的
open my $out_fh, '>', $font or die qq{Unable to open "$font" for output: $!};
Run Code Online (Sandbox Code Playgroud)这条线
$/ = undef;
Run Code Online (Sandbox Code Playgroud)
应该local $/像在别处使用的那样,否则你将永久修改其余程序和模块的输入记录分隔符.它也会在第一次从文件句柄读取后出现,因此您的程序将读取并处理一行,然后在while循环的下一次迭代中处理整个文件的其余部分