3

文字列を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

そして2番目:

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
4

3 に答える 3

6

どのような入力を取得しているのか、どこから取得しているのか、または出力を何にしたいのかは明確ではありませんが、プログラム内で使用するためにデータを UTF-8 にエンコードするべきではありません。エンコードされたバイト。プログラムに送信されている外部エンコーディングからデコードし、そのように操作する必要があります

入力が Windows-1251 で、出力が UTF-8 (?) のように聞こえますが、バックスラッシュは気を散らすものだと思います。ファイルにバックスラッシュがないか、キーボードで入力されていますか? わかりやすくするためにベースを16進数に変更すると、入力文字列は次のようになります

"\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;

出力

РАДИУС ОРАКЛ

しかし、それは不自然な状況です。文字列は実際には入力ストリームから来ているので、ストリームのエンコーディングを設定し、手動でのデコードは忘れたほうがよいでしょう。binmodeこのように、STDINから読み取る場合に使用できます

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 に設定します。これがあなたの望むものではなく、必要に応じて設定する方法がわからない場合は、お問い合わせください

于 2015-10-14T09:07:12.213 に答える
0

utf-8 端末で入力されたバックスラッシュと 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;
于 2015-10-15T05:48:58.970 に答える
0

これについて考えます:

$ perl -le 'print length("\320\300\304\310\323\321 \316\320\300\312\313")'
12

$ perl -le 'print length($ARGV[0])' "\320\300\304\310\323\321 \316\320\300\312\313"
45

ここでは、指定された文字列の文字数を受け取ります。string がperl スクリプトにある場合、perl はバックスラッシュ記号をそのコードに従って解釈することに注意してください。しかし、バックスラッシュ記号が perl スクリプトの外にある場合、それらは単なるシェル記号であり、シェルはそれらを何らかの形で解釈しないため、指定したとおりの結果が得られます。

于 2015-10-15T01:11:04.123 に答える