在Perl中打印到文件与打印到shell

我正在编写一个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;
}

在子程序process_file中,输出print“$_”;在terminal显示正确的泰米尔语Unicode字符.

然而output to the file handle $决赛是非常不同的.

%map是here.

为什么输出不同?

我该如何纠正这种行为?

我见过这个question,但这不一样.在我的情况下,终端显示正确的结果,而文件句柄输出是不同的.

解决方法

你的公开声明
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循环的下一次迭代中处理整个文件的其余部分

相关文章

忍不住在 PerlChina 邮件列表中盘点了一下 Perl 里的 Web 应用框架(巧的是 PerlBuzz 最近也有一篇相关...
bless有两个参数:对象的引用、类的名称。 类的名称是一个字符串,代表了类的类型信息,这是理解bless的...
gb2312转Utf的方法: use Encode; my $str = "中文"; $str_cnsoftware = encode("utf-8...
  perl 计算硬盘利用率, 以%来查看硬盘资源是否存在IO消耗cpu资源情况; 部份代码参考了iostat源码;...
1 简单变量 Perl 的 Hello World 是怎么写的呢?请看下面的程序: #!/usr/bin/perl print "Hello W...
本文介绍Perl的Perl的简单语法,包括基本输入输出、分支循环控制结构、函数、常用系统调用和文件操作,...