Perl:从cp1251转换为utf8

时间:2015-10-14 03:39:44

标签: perl encoding utf-8 cp1251

我尝试将字符串转换为utf8。

#!/usr/bin/perl -w
use Encode qw(encode decode is_utf8);
$str = "\320\300\304\310\323\321 \316\320\300\312\313";
Encode::from_to($str, 'windows-1251', 'utf-8');
print "converted:\n$str\n";

在这种情况下,我得到了我需要的东西:

# ./convert.pl
converted:
РАДИУС ОРАКЛ

但如果我使用外部变量:

#!/usr/bin/perl -w
use Encode qw(encode decode is_utf8);
$str = $ARGV[0];
Encode::from_to($str, 'windows-1251', 'utf-8');
print "converted:\n$str\n";

什么都没发生。

# ./convert.pl "\320\300\304\310\323\321 \316\320\300\312\313"
 converted:
\320\300\304\310\323\321 \316\320\300\312\313

这是第一个例子的转储:

SV = PV(0x1dceb78) at 0x1ded120
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1de7970 "\320\300\304\310\323\321 \316\320\300\312\313"\0
CUR = 12
LEN = 16

第二个:

SV = PV(0x1c1db78) at 0x1c3c110
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1c5e7e0 "\\320\\300\\304\\310\\323\\321 \\316\\320\\300\\312\\313"\0
CUR = 45
LEN = 48

我尝试过这种方法:

#!/usr/bin/perl -w
use Devel::Peek;
$str = pack 'C*', map oct, $ARGV[0] =~ /\\(\d{3})/g;
print Dump ($str);

# ./convert.pl "\320\300\304\310\323\321 \316\320\300\312\313"

SV = PV(0x1c1db78) at 0x1c3c110
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1c5e7e0 "\320\300\304\310\323\321\316\320\300\312\313"\0
CUR = 11
LEN = 48

但同样不是我需要的。你能帮我把结果写成第一个脚本吗?

使用后

($str = shift) =~ s/\\([0-7]+)/chr oct $1/eg
按照鲍罗丁的建议,我得到了这个

SV = PVMG(0x13fa7f0) at 0x134d0f0
  REFCNT = 
  FLAGS = (SMG,POK,pPOK)
  IV = 0
  NV = 0
  PV = 0x1347970 "\320\300\304\310\323\321 \316\320\300\312\313"\0
  CUR = 12
  LEN = 16
  MAGIC = 0x1358290 
    MG_VIRTUAL = &PL_vtbl_mglob
    MG_TYPE = PERL_MAGIC_regex_global(g)
    MG_LEN = -1

3 个答案:

答案 0 :(得分:6)

目前尚不清楚您输入的输入,输入的输入或输出的输入,但您不应将数据编码为UTF-8以供在内使用该程序,因为你想处理字符而不是编码字节。您应该从正在发送到程序的任何外部编码中解码它并像它一样使用它

听起来输入是Windows-1251,输出是UTF-8(?),我认为反斜杠是一种分心。文件中没有反斜杠或键盘上键入了吗?因此,为了清晰起见,将基数更改为十六进制,输入字符串就像这样

"\xD0\xC0\xC4\xC8\xD3\xD1\x20\xCE\xD0\xC0\xCA\xCB"

并且你想将它转换为Perl字符串,用它做一些东西,然后将它打印到输出。如果您在Linux机器上并且想要从原始输入字节显式解码它,那么您需要编写类似这样的内容

use utf8;
use strict;
use warnings;
use feature 'say';

use open qw/ :std OUT :encoding(UTF-8) /;
use Encode qw/ decode /;

my $str = "\xD0\xC0\xC4\xC8\xD3\xD1\x20\xCE\xD0\xC0\xCA\xCB";

$str = decode('Windows-1251', $str);

say $str;

输出

РАДИУС ОРАКЛ

但这是一种人为的情况。该字符串实际上来自输入流,因此设置流的编码并忘记手动解码更好。如果您正在阅读STDIN,可以使用binmode,例如

binmode STDIN, 'encoding(Windows-1251)';

然后从STDIN输入的文本将从Windows-1251编码的字节隐式转换为字符串。或者,如果您在自己的句柄上打开文件,则可以将编码放入open调用

open my $fh, '<:encoding(Windows-1251)', $file or die $!;

然后您不需要添加binmode

正如我所说,我假设您的输出是UTF-8,并且在行上方的程序中

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

将所有输出文件句柄设置为默认的UTF-8编码。 :std还将内置句柄STDOUT和STDERR设置为UTF-8。如果这不是你想要的,你可以根据需要弄清楚如何设置它,那么请问

答案 1 :(得分:0)

想一想:

$link = "hi"; 

$message->setBody($link."Loser");  

这里我们收到给定字符串中的字符数。 请注意,当字符串 perl脚本中时,perl会根据其代码解释反向符号。但是如果反斜杠符号在perl脚本之外,那么只是 shell符号而shell不会以某种方式解释它们,所以你得到的就是你给的。

答案 2 :(得分:0)

将utf-8终端中输入的反斜杠和八进制数字转换为cp1251的几种简单方法:

$str = perl -e 'print "$ARGV[0]"' | iconv -f windows-1251;
print $str;

$str = pack "C*", map oct()? oct : 32, $ARGV[0] =~ / \d{3} | \s /gx;
print $str;