gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 14:11:16 27 4
gpt4 key购买 nike

我正在编写一个 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_fileprint "$_"; 的输出在 terminal 中显示正确的泰米尔语 Unicode 字符.

然而 output to the file handle $final非常不同。
%maphere .

为什么输出不同?

我该如何纠正这种行为?

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

最佳答案

你的公开声明

open my $final, '>:utf8', "$result";

将您的文件句柄设置为期望字符,然后在输出时编码为 UTF-8 序列。但是您从 %map 发送预编码的字节序列哈希,这会导致这些字节被视为字符并由 Perl IO 再次编码

相反,您的终端设置为期望 UTF-8 编码的数据,但 STDOUT根本没有设置为进行任何编码( use open ':std' 本身没有影响,见下文),因此它通过未更改的方式传递您的 UTF-8 编码字节,这恰好是终端所期望的

顺便说一句,您设置了默认的打开模式 :encoding(UTF-8)对于输入和输出流
use open ':encoding(UTF-8)'

但在您调用 open 时已将其覆盖. :utf8 mode 进行了从宽字符到字节序列的非常基本的转换,但是 :encoding(UTF-8)更有用,因为它检查每个被打印的字符是一个有效的 Unicode 值。很有可能它会遇到这样的错误,最好允许默认值并只写
open my $final, '>', $result;

为了保持干净整洁,您的程序应该以字符形式运行,并且文件句柄应该设置为在打印这些字符时将这些字符编码为 UTF-8

您可以将 UTF-8 设置为所有新打开的文件句柄的默认编码以及 STDINSTDOUT通过增加
use open qw/ :std :encoding(utf-8) /;

到您的程序顶部( :encoding(utf-8):utf8 更可取)并删除对 encode 的所有调用.你说得差不多了,但是 :std:encoding(utf-8)需要在同一个 use陈述

您还应该添加
use utf8;

在最顶部,以便您可以在程序本身中使用 UTF-8 字符

你也有一些偶然的错误。例如
  • 在声明中
    open my $in, '<', "$font" || die "can't open file: $!";

    引用单个标量变量(如 $font)几乎总是错误的。除非它碰巧是一个对象并且你想调用字符串化方法

    您需要or而不是 || , 否则你只是在测试 $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;

    应该是 local $/正如您在其他地方使用的那样,否则您将永久修改其余程序和模块的输入记录分隔符。它也出现在第一次从文件句柄读取之后,因此您的程序将读取并处理一行,然后在 while 的下一次迭代中读取并处理文件的其余部分。循环
  • 关于perl - 在 Perl 中打印到文件与打印到 shell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31940545/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com