Perl 中的 Unicode,mkdir 练习
Unicode in perl, mkdir exercise
我目前正在学习 Unicode 编程的艺术,并将其应用到个人项目中。很快我意识到做对真的很难,甚至理解如果你做对了:如果工具不对,你可能会错误地评估你的工作结果。
我在这个练习中的小目标是了解我应该传递给 mkdir
什么与对 File::Path::make_path
有好处。换句话说:他们期望什么?他们会根据语言环境处理编码,还是我应该为他们做?
我编写了以下脚本,这些脚本从 @ARGV
获取参数,并为每个参数创建目录 $_
,同时使用两个函数以及编码和解码的来源。
#!/usr/bin/perl
use warnings;
use strict;
use utf8;
use v5.16;
use Encode;
use Encode::Locale;
use File::Path qw/make_path/;
use File::Spec;
# Everything under the './tree' directory
mkdir 'tree';
mkdir File::Spec->catdir('tree', $_)
for ('mkdir', 'mkdir_enc', 'make_path', 'make_path_enc');
foreach (map decode(locale => $_) => @ARGV) {
mkdir File::Spec->catdir('tree', 'mkdir', $_);
mkdir encode(locale_fs => File::Spec->catdir('tree', 'mkdir_enc', $_));
make_path(File::Spec->catdir('tree', 'make_path', $_));
make_path(encode(locale_fs => File::Spec->catdir('tree', 'make_path_enc', $_)));
}
我执行的脚本如下:
./unicode_mkdir.pl a→b←c
我期望的是:
tree/mkdir
[x] 或 tree/mkdir_enc
包含名为乱码的目录;
tree/make_path
[x] 或 tree/make_path_enc
包含名为乱码的目录;
我非常惊讶地发现所有版本都可以正常工作。我用 find
:
验证了它
$ find tree
tree
tree/mkdir_enc
tree/mkdir_enc/a→b←c
tree/mkdir
tree/mkdir/a→b←c
tree/make_path_enc
tree/make_path_enc/a→b←c
tree/make_path
tree/make_path/a→b←c
我意识到 tree
命令让它变得如此错误......(一种很常见的疾病)但至少我可以看到结果都是一样的:
$ tree tree
tree
├── make_path
│ └── a262b260c
├── make_path_enc
│ └── a262b260c
├── mkdir
│ └── a262b260c
└── mkdir_enc
└── a262b260c
8 directories, 0 files
一条ls -R
命令似乎证实了这一点。
$ ls -R tree
tree:
make_path make_path_enc mkdir mkdir_enc
tree/make_path:
a→b←c
tree/make_path/a→b←c:
tree/make_path_enc:
a→b←c
tree/make_path_enc/a→b←c:
tree/mkdir:
a→b←c
tree/mkdir/a→b←c:
tree/mkdir_enc:
a→b←c
tree/mkdir_enc/a→b←c:
所以我的问题是:
我在代码方面做得对吗(当然不是)?
我在文件系统方面做得对吗?
mkdir
和make_path
如何找出错误并改正?
或者也许我只是 "reverse-lucky"(这种幸运不会让你意识到你的错误,因为 在你的情况下是吗?那我怎么才能有效地测试出来呢?
有什么提示吗?
- How can
mkdir
and make_path
figure out and fix the wrong one?
Perl 字符串有一个 "UTF-8 flag" 表示它们包含的 "characters" 是 Unicode 字符还是八位字节(八位字节)。您可以使用 utf8::is_utf8
函数(参见 http://perldoc.perl.org/utf8.html)来检查是否为给定字符串设置了 UTF-8 标志;或者您可以使用 Devel::Peek
模块中的 Dump
,它打印出标量的所有内容,包括设置的标志列表。
所以mkdir
和make_path
不需要做太疯狂的事情;他们可以通过将它们编码为八位字节字符串来处理 Unicode 字符串,就像您在调用 encode
.
时所做的那样
(不幸的是,UTF-8 标志有很多怪癖,并不是所有的函数都支持它;例如,encode
不关心它的参数是否设置了那个标志,它只是相信你不会在字符串上调用它,除非字符串应该被解释为 Unicode 字符序列。但是如果你使用现代的、支持 Unicode 的库和 use utf8
,并且只做所有 Unicode- ishly 除非专门与面向字节的外部系统交互(你使用 Encode::encode
和 Encode::decode
),你应该没问题。)
- Am I doing it right code-wise ('course not)?
- Am I doing it right filesystem-wise?
是的,但我认为您应该多注意错误情况。如果您的输入无法在语言环境字符集中表示怎么办?如果可以,但结果不是您的操作系统或文件系统中的有效文件名怎么办?
要解决这个问题,您应该进行两到三处更改:
- 您应该向
Encode::encode
提供明确的第三个参数,以指定它应如何处理不可编码的字符。 (默认行为是用替换字符替换它们,例如 ?
用于 US-ASCII;这可能不是您想要的。)
- 您应该检查
mkdir
的 return 值。
- 您可能想使用
make_path
的 error
选项,并检查生成的 arrayref;或者,您可能希望将 make_path
包装在 eval
块中。
我目前正在学习 Unicode 编程的艺术,并将其应用到个人项目中。很快我意识到做对真的很难,甚至理解如果你做对了:如果工具不对,你可能会错误地评估你的工作结果。
我在这个练习中的小目标是了解我应该传递给 mkdir
什么与对 File::Path::make_path
有好处。换句话说:他们期望什么?他们会根据语言环境处理编码,还是我应该为他们做?
我编写了以下脚本,这些脚本从 @ARGV
获取参数,并为每个参数创建目录 $_
,同时使用两个函数以及编码和解码的来源。
#!/usr/bin/perl
use warnings;
use strict;
use utf8;
use v5.16;
use Encode;
use Encode::Locale;
use File::Path qw/make_path/;
use File::Spec;
# Everything under the './tree' directory
mkdir 'tree';
mkdir File::Spec->catdir('tree', $_)
for ('mkdir', 'mkdir_enc', 'make_path', 'make_path_enc');
foreach (map decode(locale => $_) => @ARGV) {
mkdir File::Spec->catdir('tree', 'mkdir', $_);
mkdir encode(locale_fs => File::Spec->catdir('tree', 'mkdir_enc', $_));
make_path(File::Spec->catdir('tree', 'make_path', $_));
make_path(encode(locale_fs => File::Spec->catdir('tree', 'make_path_enc', $_)));
}
我执行的脚本如下:
./unicode_mkdir.pl a→b←c
我期望的是:
tree/mkdir
[x] 或tree/mkdir_enc
包含名为乱码的目录;tree/make_path
[x] 或tree/make_path_enc
包含名为乱码的目录;
我非常惊讶地发现所有版本都可以正常工作。我用 find
:
$ find tree
tree
tree/mkdir_enc
tree/mkdir_enc/a→b←c
tree/mkdir
tree/mkdir/a→b←c
tree/make_path_enc
tree/make_path_enc/a→b←c
tree/make_path
tree/make_path/a→b←c
我意识到 tree
命令让它变得如此错误......(一种很常见的疾病)但至少我可以看到结果都是一样的:
$ tree tree
tree
├── make_path
│ └── a262b260c
├── make_path_enc
│ └── a262b260c
├── mkdir
│ └── a262b260c
└── mkdir_enc
└── a262b260c
8 directories, 0 files
一条ls -R
命令似乎证实了这一点。
$ ls -R tree
tree:
make_path make_path_enc mkdir mkdir_enc
tree/make_path:
a→b←c
tree/make_path/a→b←c:
tree/make_path_enc:
a→b←c
tree/make_path_enc/a→b←c:
tree/mkdir:
a→b←c
tree/mkdir/a→b←c:
tree/mkdir_enc:
a→b←c
tree/mkdir_enc/a→b←c:
所以我的问题是:
我在代码方面做得对吗(当然不是)?
我在文件系统方面做得对吗?
mkdir
和make_path
如何找出错误并改正?或者也许我只是 "reverse-lucky"(这种幸运不会让你意识到你的错误,因为 在你的情况下是吗?那我怎么才能有效地测试出来呢?
有什么提示吗?
- How can
mkdir
andmake_path
figure out and fix the wrong one?
Perl 字符串有一个 "UTF-8 flag" 表示它们包含的 "characters" 是 Unicode 字符还是八位字节(八位字节)。您可以使用 utf8::is_utf8
函数(参见 http://perldoc.perl.org/utf8.html)来检查是否为给定字符串设置了 UTF-8 标志;或者您可以使用 Devel::Peek
模块中的 Dump
,它打印出标量的所有内容,包括设置的标志列表。
所以mkdir
和make_path
不需要做太疯狂的事情;他们可以通过将它们编码为八位字节字符串来处理 Unicode 字符串,就像您在调用 encode
.
(不幸的是,UTF-8 标志有很多怪癖,并不是所有的函数都支持它;例如,encode
不关心它的参数是否设置了那个标志,它只是相信你不会在字符串上调用它,除非字符串应该被解释为 Unicode 字符序列。但是如果你使用现代的、支持 Unicode 的库和 use utf8
,并且只做所有 Unicode- ishly 除非专门与面向字节的外部系统交互(你使用 Encode::encode
和 Encode::decode
),你应该没问题。)
- Am I doing it right code-wise ('course not)?
- Am I doing it right filesystem-wise?
是的,但我认为您应该多注意错误情况。如果您的输入无法在语言环境字符集中表示怎么办?如果可以,但结果不是您的操作系统或文件系统中的有效文件名怎么办?
要解决这个问题,您应该进行两到三处更改:
- 您应该向
Encode::encode
提供明确的第三个参数,以指定它应如何处理不可编码的字符。 (默认行为是用替换字符替换它们,例如?
用于 US-ASCII;这可能不是您想要的。) - 您应该检查
mkdir
的 return 值。 - 您可能想使用
make_path
的error
选项,并检查生成的 arrayref;或者,您可能希望将make_path
包装在eval
块中。