基本上我有一个数据库,我从中获取$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
,则特殊字符为垃圾(ä变为Ã),其余为OK。
使用decode
,一切都很好,除了名称中包含特殊字符的行有几个<
太多。
为什么?我该如何删除它们?
修改:swrite
来自perldoc perlform
sub swrite {
my $format = shift;
$^A = '';
formline($format, @_);
return $^A;
}
EDIT2: 问题不在于终端和STDOUT。我用:
use Mail::Sender;
use vars qw($sender);
#...
$sender->MailMsg({to => $mailto,
cc=> "",
bcc => "",
subject => "subject",
msg => $send});
接收电子邮件时,这些字符显示得很糟糕。
编辑3:
我得到的数据已经被扰乱了。我得到'Ã'而不是'ä',这就是我的格式失败的原因,因为使用解码时字符的数量会减少。
答案 0 :(得分:4)
问题是format
引擎不理解您的UTF-8;它认为每个字节都是一个字符。我实际上并不知道你是否可以formline
(swrite
的基本机制)说Unicode,但试试这个:
use open qw( :std :encoding(UTF-8) );
尝试尽可能广泛地应用UTF-8编码。
您可能需要在此处跳过decode
用法。
答案 1 :(得分:4)
我的最小测试用例似乎认为格式处理Unicode就好了:
perl -MEncode -e 'formline("X@<<X", Encode::decode("utf-8","ほげぼげ")); print $^A'
输出为三个字符,如预期的那样。但无论如何,format
被严重弃用。是时候改用其他东西了。
答案 2 :(得分:3)
如果您使用swrite
中的perldoc perlform
功能,则问题是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(这类似于命令行上混乱的-CSD):
PERL_UNICODE=SDL perl script.pl
或
export PERL_UNICODE=SDL
perl script.pl
还有其他方式可以告诉STDOUT
期待UTF-8,但我无法记住它们(我将export PERL_UNICODE=SDL
放在我的.profile
中很久以前)。
如果问题是您的终端,那么您需要正确配置它或获得不同的终端。上面的代码适用于正确配置的终端,因此您可以将其用作测试。
答案 3 :(得分: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 :(得分:1)
我不知道格式或swrite,但我确实知道您的电子邮件问题。
您在收到的电子邮件中看到的字符是UTF-8。但是,您的邮件程序默认设置为显示其他内容(如Windows-1252或Latin-1)。
解决方案是在电子邮件中添加一个标题,通知邮件程序有关字符编码的信息,以便它可以正确显示。您需要添加到电子邮件的标题是:
Mime-version: 1.0
Content-type: text/plain; charset="UTF-8"
(或另一个字符集,确保它与电子邮件正文相对应)
此外,您可能希望将电子邮件编码为7bit编码,例如“quoted-printable”,并添加相应的标题:
Content-transfer-encoding: quoted-printable
可以使用MIME :: QuotedPrint模块完成最后一次编码。