我有一個 Perl 腳本,它的任務是對齊 UTF8 編碼中的字串并將它們寫入檔案,腳本的一部分如下所示:
#!/usr/bin/perl
use strict;
use utf8;
use locale;
use warnings;
...
my $length_sv = 9;
open my $out, '>>:encoding(UTF-8)', "filename" or warn "Could not open file - $!" and exit(1);
my ($tid, $cid, $v3, $l, $v5, $sub) = $_ =~ /^\{"id":(\d ),"customer_id":(\d )(.*?)_login":"(\w{1,10})"(.*?)"subject":"(.*?)"/;
my $subc = substr($sub, 0, $length_sv);
say $subc;
my $string = sprintf "| %-5s | %-1s | %-9s | %-${length_sv}s | %-11s | %-10s|","$time","$num","$tid","$subc","$cid","$l";
say $string;
say $out $string;
close $out;
運行腳本后,在 STDOUT 中我們得到以下結論:
Тест Mark
| 11:00 | 1 | 1234567 | Тест Mark | 10101012 | login |
但是同一行被寫入檔案并出現錯誤:
$ cat filename
| 11:00 | 1 | 1234567 | D¢Dμ?? Mark | 10101012 | login |
我希望Тест Mark寫入該列,但將一列D¢Dμ?? Mark添加到檔案中。
我嘗試在腳本中添加這樣一行:
binmode($out,':utf8');
不幸的是它沒有幫助。你怎么能解決這個問題?
uj5u.com熱心網友回復:
我對你的錯誤的建議:
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use v5.10;
open my $fh0, '>:encoding(UTF-8)', './russian_text' or die $!;
print $fh0 'Тест';
close( $fh0 );
say __LINE__, ': ', `cat ./russian_text`;
foreach my $mode ( '<', '<:encoding(UTF-8)' ) {
open my $fh1, $mode, './russian_text' or die $!;
my $line = <$fh1>;
chomp $line;
open my $fh2, '>:encoding(UTF-8)', './russian_out' or die $!;
print $fh2 "Mode: $mode, line: ", $line;
close( $fh2 );
say `cat ./russian_out`;
}
從perlopentut:
但是不要在沒有先設定默認編碼的情況下使用裸的“<”。否則,Perl 無法知道您擁有的文本檔案的多種可能型別中的哪一種,并且 Perl 將不知道如何將檔案中的資料正確映射為它可以使用的實際字符。其他常見的編碼格式包括“ASCII”、“ISO-8859-1”、“ISO-8859-15”、“Windows-1252”、“MacRoman”,甚至“UTF-16LE”。有關編碼的更多資訊,請參閱 perlitut。
如果您的資料來自其他地方 - 您仍然應該正確解碼資料。Perl 無法自動計算編碼:
#!/usr/bin/env perl
use strict;
use warnings;
use Encode qw(decode);
# onliner for test server: perl -Mojo -E 'a(sub ($c) { $c->render(text => "Тест") })->start' daemon
my $web_data = `curl localhost:3000`;
my $decoded = decode('UTF-8', $web_data );
open my $fh0, '>:encoding(UTF-8)', 'foo';
open my $fh1, '>:encoding(UTF-8)', 'bar';
print $fh0 $web_data;
print $fh1 $decoded;
在此處閱讀有關編碼/解碼的資訊:perlunitut
uj5u.com熱心網友回復:
解碼您的輸入并編碼您的輸出。
錯誤 #1:$sub因此$subc包含使用 UTF-8 編碼的文本,但列印到帶有編碼層的檔案句柄需要解碼文本。結果是您最終在檔案中得到“雙重編碼”文本。您需要解碼您的輸入。
錯誤 #2:修復第一個錯誤將揭示另一個錯誤。您向檔案句柄添加了一個編碼層,但未向 STDOUT 添加。要解決此問題,請添加一個編碼層來解碼您的 STDOUT。
固定版本:
# Adds an encoding/decoding layer to STDIN, STDOUT and STDERR.
# Sets the default :encoding for handles opened in scope (incl via ARGV).
use open ':std', ':encoding(UTF-8)';
use JSON qw( from_json );
# Same as `open(my $fh, '>:encoding(UTF-8)', $qfn)` because of `use open`
open(my $fh, '>', $qfn)
or die("Can't open \"$qfn\": $!\n");
while ( my $json = <> ) {
my $data = from_json($_);
my $tid = $data->{id};
my $cid = $data->{customer_id};
my ($l) = map $data->{$_}, grep /_login\z/, keys(%$data);
my $sub = $data->{subject};
my $subc = substr($sub, 0, $length_sv);
say $subc;
my $string = sprintf "| %-5s | %-1s | %-9s | %-${length_sv}s | %-11s | %-10s|",
$time, $num, $tid, $subc, $cid, $l;
say $string;
say $fh $string;
}
我還用一個合適的替換了你的手動 JSON 決議器。
uj5u.com熱心網友回復:
我的腳本的一個例子:
#!/usr/bin/perl
use strict;
use utf8;
#use locale;
use warnings;
my $curl = qq( curl -s "https://example.com/all" -H "authorization: Bearer $token" \\
--data-raw '{"scope":[{"by_subject":{"login":['"$id"']}}],"page":0,"page_size":10}' \\
--compressed 2>/dev/null );
my $response = `$curl`;
$response =~ s/\},\{/\}###\{/g;
my @array = split(/###/, $response);
my $length_sv = 9;
#open my $out, '>>:encoding(UTF-8)', "filename" or warn "Could not open file - $!" and exit(1);
open my $out, '>>', "filename" or warn "Could not open file - $!" and exit(1);
foreach(@array) {
my ($tid, $cid, $v3, $l, $v5, $sub) = $_ =~ /^\{"id":(\d ),"customer_id":(\d )(.*?)_login":"(\w{1,10})"(.*?)"subject":"(.*?)"/;
my $subc = substr($sub, 0, $length_sv);
say $subc;
my $string = sprintf "| %-5s | %-1s | %-9s | %-${length_sv}s | %-11s | %-10s|","$time","$num","$tid","$subc","$cid","$l";
say $string;
say $out $string;
}
close $out;
我洗掉了該行use locale并替換open my $out, '>>:encoding(UTF-8)'為open my $out, '>>'. 之后,檔案以正確的編碼寫入。
- 您應該為“Тест”來自的輸入檔案設定編碼。
錯誤 #1:$sub 和 $subc 包含使用 UTF-8 編碼的文本,但列印到帶有編碼層的檔案句柄需要解碼文本。結果是您最終在檔案中得到“雙重編碼”文本。您需要解碼您的輸入。
你能告訴我如何正確指定來自外部程式的傳入資料的編碼嗎?
錯誤 #2:修復第一個錯誤將揭示另一個錯誤。您向檔案句柄添加了一個編碼層,但未向 STDOUT 添加。要解決此問題,請添加一個編碼層來解碼您的 STDOUT。
我相信這樣做的正確方法是添加:
binmode(STDOUT,':utf8');
問題仍然是輸入資料的編碼指示。
我以這種方式獲得輸入:
my $curl = qq( curl -s "https://example.com/all" -H "authorization: Bearer $token" \\
--data-raw '{"scope":[{"by_subject":{"login":['"$id"']}}],"page":0,"page_size":10}' \\
--compressed 2>/dev/null );
my $response = `$curl`;
謝謝您的反饋!你幫了很多忙!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/316279.html
