"Turn Off" binmode(STDOUT, ":utf8") 本地
"Turn Off" binmode(STDOUT, ":utf8") Locally
我的脚本开头有以下块:
#!/usr/bin/perl5 -w
use strict;
binmode(STDIN, ":utf8");
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");
在某些子程序中,当有其他编码时(来自遥远的子程序),当接收西里尔或其他字符时,数据将无法正确显示。导致问题的是 "binmode"。
我可以在本地 "turn off" binmode utf8,仅用于子例程吗?
我无法删除全局 binmode 设置,也无法更改远程编码。
实现此目的的一种方法是 "dup" STD
句柄,将复制的文件句柄设置为使用 :raw
层,并将其分配给本地版本的 STD
句柄。比如下面的代码
binmode(STDOUT, ':utf8');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
{
open(my $duped, '>&', STDOUT);
# The ':raw' argument could also be omitted.
binmode($duped, ':raw');
local *STDOUT = $duped;
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
close($duped);
}
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
打印
unix, perlio, utf8
unix, perlio
unix, perlio, utf8
在我的系统上。
我喜欢@nwellnhof 的方法。只处理 Unicode 和 ASCII——很少有人享受——我的直觉是让字节保持原样,并在需要时有选择地使用 Encode
到 decode()/encode()
。如果您能够确定哪些数据源有问题,您可以 filter/insert decode
在处理它们时。
% file koi8r.txt
koi8r.txt: ISO-8859 text
% cat koi8r.txt
������ �� ����� � ������� ���. ���
���� ����� ������ ����� �����.
% perl -CO -MEncode="encode,decode" -E 'say decode("koi8-r", <>) ;' koi8r.txt
Американские суда находятся в международных водах. Япония
你可以使用 Scope::Guard - lexically-scoped resource management 之类的东西来确保当你离开范围时它被设置回 :utf8
,无论如何(return,死亡,无论如何):
#!/usr/bin/perl -w
use strict;
use Scope::Guard qw(guard);
binmode(STDOUT, ':utf8');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
{
# When guard goes out of scope, this sub is guaranteed to be called:
my $guard = guard {
binmode(STDOUT, ':utf8');
};
binmode(STDOUT, ':raw');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
}
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
或者,如果您不想包含像 Scope::Guard 这样的新依赖项(Scope::Guard 非常适合这种本地化...):
#!/usr/bin/perl -w
use strict;
binmode(STDOUT, ':utf8');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
{
my $guard = PoorMansGuard->new(sub {
binmode(STDOUT, ':utf8');
});
binmode(STDOUT, ':raw');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
}
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
package PoorMansGuard;
sub new {
my ($class, $sub) = @_;
bless { sub => $sub }, $class;
}
sub DESTROY {
my ($self) = @_;
$self->{sub}->();
}
我的脚本开头有以下块:
#!/usr/bin/perl5 -w
use strict;
binmode(STDIN, ":utf8");
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");
在某些子程序中,当有其他编码时(来自遥远的子程序),当接收西里尔或其他字符时,数据将无法正确显示。导致问题的是 "binmode"。
我可以在本地 "turn off" binmode utf8,仅用于子例程吗?
我无法删除全局 binmode 设置,也无法更改远程编码。
实现此目的的一种方法是 "dup" STD
句柄,将复制的文件句柄设置为使用 :raw
层,并将其分配给本地版本的 STD
句柄。比如下面的代码
binmode(STDOUT, ':utf8');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
{
open(my $duped, '>&', STDOUT);
# The ':raw' argument could also be omitted.
binmode($duped, ':raw');
local *STDOUT = $duped;
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
close($duped);
}
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
打印
unix, perlio, utf8
unix, perlio
unix, perlio, utf8
在我的系统上。
我喜欢@nwellnhof 的方法。只处理 Unicode 和 ASCII——很少有人享受——我的直觉是让字节保持原样,并在需要时有选择地使用 Encode
到 decode()/encode()
。如果您能够确定哪些数据源有问题,您可以 filter/insert decode
在处理它们时。
% file koi8r.txt
koi8r.txt: ISO-8859 text
% cat koi8r.txt
������ �� ����� � ������� ���. ���
���� ����� ������ ����� �����.
% perl -CO -MEncode="encode,decode" -E 'say decode("koi8-r", <>) ;' koi8r.txt
Американские суда находятся в международных водах. Япония
你可以使用 Scope::Guard - lexically-scoped resource management 之类的东西来确保当你离开范围时它被设置回 :utf8
,无论如何(return,死亡,无论如何):
#!/usr/bin/perl -w
use strict;
use Scope::Guard qw(guard);
binmode(STDOUT, ':utf8');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
{
# When guard goes out of scope, this sub is guaranteed to be called:
my $guard = guard {
binmode(STDOUT, ':utf8');
};
binmode(STDOUT, ':raw');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
}
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
或者,如果您不想包含像 Scope::Guard 这样的新依赖项(Scope::Guard 非常适合这种本地化...):
#!/usr/bin/perl -w
use strict;
binmode(STDOUT, ':utf8');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
{
my $guard = PoorMansGuard->new(sub {
binmode(STDOUT, ':utf8');
});
binmode(STDOUT, ':raw');
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
}
print(join(', ', PerlIO::get_layers(STDOUT)), "\n");
package PoorMansGuard;
sub new {
my ($class, $sub) = @_;
bless { sub => $sub }, $class;
}
sub DESTROY {
my ($self) = @_;
$self->{sub}->();
}