【问题标题】:How can I use Unicode characters when I write to Perl's format?当我写入 Perl 的格式时,如何使用 Unicode 字符?
【发布时间】:2010-11-21 01:37:15
【问题描述】:

基本上我有一个数据库,我可以从中获取$lastname$firstname$rid$since$times$ip

使用 Perl 脚本,我格式化数据以通过电子邮件发送。由于$lastname$firstname 可以包含特殊字符(例如ä、ü、ß、é、...),我首先对字符串进行解码。

my $fullname = decode("utf8", $lastname) . ', ' . decode("utf8", $firstname);
my $send = swrite(<<'END', $ip, $fullname, $rid, $since, $times);
@<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<< @>>END

没有decode,特殊字符是垃圾(ä变成À),其余的都可以。
使用decode,一切都很好,除了名称包含特殊字符的行有几个&lt; 太多。

这是为什么呢?以及如何删除它们?

编辑:swrite 来自perldoc perlform

sub swrite {
  my $format = shift;
  $^A = '';
  formline($format, @_);
  return $^A;
}

编辑2: 问题不在于终端,也不在于 STDOUT。我用:

use Mail::Sender;
use vars qw($sender);
#...
$sender->MailMsg({to => $mailto, 
  cc=> "", 
  bcc => "", 
  subject => "subject", 
  msg => $send});

而且收到邮件时字符显示不好。

编辑 3:
我得到的数据已经被打乱了。我得到 'À' 而不是 'ä',这就是我的格式失败的原因,因为使用解码时字符数会减少。

【问题讨论】:

  • Perl 不提供swrite 函数。您使用的是来自perldoc perlform 的那个还是别的什么?如果没有这些信息,任何帮助都只是猜测。
  • 对不起,我忘记添加 swrite 的代码了。
  • 您使用的是什么终端/操作系统?这可能会影响事情。
  • 您的问题似乎是电子邮件客户端无法处理 UTF-8 纯文本。您可能需要将电子邮件消息写入 MIME Multipart 并将文本类型指定为 UTF-8。
  • @Paul:我使用在 Debian "Lenny" 上运行的 xen 虚拟机 (2.6.18-6-xen-amd64)。数据库是 PostgresSQL 7.4 版

标签: perl email unicode format


【解决方案1】:

我的最小测试用例似乎认为格式可以很好地处理 Unicode:

perl -MEncode -e 'formline("X@<<X", Encode::decode("utf-8","ほげぼげ")); print $^A'

正如预期的那样,输出是三个字符。但无论如何,format 已被严重弃用。是时候改用其他东西了。

【讨论】:

    【解决方案2】:

    问题在于format 引擎不理解您的UTF-8;它认为每个字节都是一个字符。我实际上不知道你是否可以让formlineswrite 的底层机制)说 Unicode,但试试这个:

    use open qw( :std :encoding(UTF-8) );
    

    这会尝试尽可能广泛地应用 UTF-8 编码。

    您可能需要跳过decode 的使用情况。

    【讨论】:

    • 我在 ./test.pl 第 1 行收到“对于“-CSD”选项来说太晚了。”我做错了什么?
    • 稍微研究了一下,似乎在某些时候在 shebang 线上使用 -C 变得不受支持。编辑以提供我希望的替代品。
    【解决方案3】:

    我从未有过学习格式的愿望。这是一个糟糕的答案,因为我无法对您的问题和/或潜在的解决方案提供任何见解,但其他人已经这样做了。我将提供两个替代建议。

    第一个,Perl6::Form 应该是有用的,更好 format 虽然我从来没有使用过它,直到我今天把这个例子放在一起。另一方面,我使用了Text::Table,它对于以纯文本创建表格非常有用(大多数时候,我只是生成 HTML,但电子邮件仍然是纯文本明显更好的地方之一)。

    Perl6::Form 例子:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Perl6::Form;
    
    my @data = (
        ['127.0.0.1', 'Johnny Smithey', 'JLNSJIV', 14, 5],
        ['127.0.0.2', 'Ömer Seyfettin Şınas', 'OSS3', 25, 5],
    );
    
    for my $data_ref ( @data ) {
        print format_data($data_ref);
    }
    
    sub format_data {
        my ($data) = @_;
        return form
            '{<<<<<<<<<<<<<<<} {<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<} ' .
            '{<<<<<<<<<<} {<<<<<<<<<<<<<<} {>>}',
            @$data;
    }
    

    Text::Table 例子:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Text::Table;
    
    my %common_options = (
        align => 'left',
        title_align => 'center',
    );
    
    my $sep = \' ';
    
    my $table = Text::Table->new(
        {
            title  => 'IP Address',
            sample => '<' x 15,
            %common_options,
        },
        $sep,
        {
            title => 'Full Name',
            sample => '<' x 34,
            %common_options,
        },
        $sep,
        {
            title => 'RID',
            sample => '<' x 10,
            %common_options,
        },
        $sep,
        {
            title => 'Since',
            sample => '<' x 14,
            %common_options,
        },
        $sep,
        {
            title => 'Times',
            sample => '>' x 2,
            align => 'right',
            title_align => 'center'
        },
    );
    
    $table->rule('');
    
    $table->load(
    ['127.0.0.1', 'Johnny Smith-Jones', 'JLNSJIV', '20090814010203', 5],
    ['127.0.0.2', 'Ömer Seyfettin Şınas', 'OSS3', '20071211101112', 3],
    ['192.168.172.144', 'Jane Doe', 'JD156', '20080101010101', 1],
    );
    
    print $table->table;
    

    【讨论】:

    【解决方案4】:

    如果您使用perldoc perlform 中的swrite 函数,您的问题是STDOUT 没有设置为UTF-8,或者您的终端无法处理UTF-8。对于第一种情况,您有几个选择。首先是使用binmode告诉STDOUT期待UTF-8:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Carp;
    
    sub swrite {
        croak "usage: swrite PICTURE ARGS" unless @_;
        my $format = shift;
        $^A = "";
        formline($format, @_);
        return $^A;
    }
    
    my $fmt = "@<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<< @>>";
    
    binmode STDOUT, ":utf8";
    
    my ($ip, $rid, $since, $times) = qw/1.1.1.1 5 2009-08-19 20/;
    my $firstname = "Ch\x{e4}s";
    my $lastname  = "\x{d6}wens";
    my $fullname  = "$lastname, $firstname";
    my $send      = swrite $fmt, $ip, $fullname, $rid, $since, $times;
    print "$send\n";
    

    另一个选项是将 PERL_UNICODE 环境变量设置为 SDL(这类似于命令行中的 Chaos 的 -CSD):

    PERL_UNICODE=SDL perl script.pl
    

    export PERL_UNICODE=SDL
    perl script.pl
    

    还有其他方法可以告诉 STDOUT 期待 UTF-8,但我不记得它们了(我很久以前把 export PERL_UNICODE=SDL 放在了我的 .profile 中)。

    如果问题是您的终端,那么您需要正确配置它或获取不同的终端。上面的代码可以在正确配置的终端上运行,因此您可以将其用作测试。

    【讨论】:

    • 其实我没有使用终端,也没有使用STDOUT。请参阅我更新的问题。
    【解决方案5】:

    我不知道格式或写作,但我知道您的电子邮件问题。

    您在收到的电子邮件中看到的字符是 UTF-8。但是,您的邮件程序默认设置为显示其他内容(如 Windows-1252 或 Latin-1)。

    解决方案是在您的电子邮件中添加一个标题,通知邮件程序有关字符编码的信息,以便它可以正确显示它。您需要添加到电子邮件的标题是:

    Mime-version: 1.0
    Content-type: text/plain; charset="UTF-8"
    

    (或其他字符集,确保它对应于电子邮件的正文)

    此外,您可能希望将电子邮件编码为 7 位编码,如“quoted-printable”,并添加相应的标头:

    Content-transfer-encoding: quoted-printable
    

    最后的编码可以通过 MIME::QuotedPrint 模块完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-22
      • 1970-01-01
      • 1970-01-01
      • 2011-08-10
      相关资源
      最近更新 更多