Как я могу использовать символы Юникода, когда я пишу в формате Perl? - PullRequest
4 голосов
/ 19 августа 2009

В основном у меня есть база данных, где я получаю $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 все в порядке, за исключением того, что строки с именем, содержащим специальные символы, имеют пару < слишком много.

Почему это? И как мне их удалить?

Редактировать: 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:
Данные, которые я получаю, уже зашифрованы. Я получаю 'Ã €' вместо 'ä', и поэтому мой формат терпит неудачу, потому что число символов уменьшается при использовании декодирования.

Ответы [ 5 ]

4 голосов
/ 19 августа 2009

Мой минимальный тестовый пример, кажется, считает, что формат прекрасно обрабатывает Unicode:

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

Выходные данные состоят из трех символов, как и ожидалось. Но в любом случае format серьезно устарело. Время использовать что-то еще.

4 голосов
/ 19 августа 2009

Проблема в том, что движок format не понимает ваш UTF-8; он думает, что каждый байт является символом. На самом деле я не знаю, сможете ли вы заставить formline (основной механизм swrite) говорить на Unicode, но попробуйте это:

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

Это попытка применить кодировку UTF-8 как можно более широко.

Возможно, вам придется пропустить использование decode с этим включенным.

3 голосов
/ 20 августа 2009

У меня никогда не было желания узнавать о форматах. Это плохой ответ, потому что я не могу предложить какую-либо информацию о вашей проблеме и / или потенциальных решениях, но другие уже сделали это. Я собираюсь предложить два предложения для замены.

Первый, 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;
3 голосов
/ 19 августа 2009

Если вы используете функцию 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 давным-давно).

Если проблема в вашем терминале, вам нужно либо правильно его настроить, либо получить другой терминал. Приведенный выше код работает на правильно настроенном терминале, поэтому вы можете использовать его в качестве теста.

1 голос
/ 18 мая 2010

Я не знаю о форматах или мошенничестве, но я знаю о вашей проблеме с электронной почтой.

Символы, которые вы видите в полученном письме, - 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...