perl中的Unicode,mkdir练习

我目前正在学习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

我期望的是:

>树/ mkdir [x]或tree / mkdir_enc包含名为gibberish的目录;
> tree / make_path [x]或tree / make_path_enc包含名为gibberish的目录;

我惊讶地发现所有版本都能正常工作.我发现它验证了它:

$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
├── make_path
│   └── a\342\206\222b\342\206\220c
├── make_path_enc
│   └── a\342\206\222b\342\206\220c
├── mkdir
│   └── a\342\206\222b\342\206\220c
└── mkdir_enc
    └── a\342\206\222b\342\206\220c

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如何解决并修复错误的问题?
>或许我只是“反向幸运”(这种幸运不允许你意识到你的错误,因为在你的情况下它?在那种情况下,我如何有效地测试它?

任何提示?

最佳答案

  1. How can mkdir and make_path figure out and fix the wrong one?

Perl字符串有一个“UTF-8标志”,指示它们包含的“字符”是否为Unicode字符,而不是八位字节(8位字节).您可以使用utf8 :: is_utf8函数(参见http://perldoc.perl.org/utf8.html)来检查是否为给定字符串设置了UTF-8标志;或者你可以使用Devel :: Peek模块中的Dump,它打印出标量的所有内容,包括设置的标志列表.

所以mkdir和make_path不需要做太疯狂的事情;他们可以通过将Unicode字符串编码为八位字符串来处理Unicode字符串,就像调用encode时一样.

(不幸的是,UTF-8标志的东西有很多怪癖,并不是所有函数都尊重它;例如,encode不关心它的参数是否设置了该标志,它只是相信你不会在它上面调用它一个字符串,除非该字符串应该被解释为一系列Unicode字符.但是如果你使用现代的,支持Unicode的库,并使用utf8,并且除了专门与面向字节的外部系统交互时,只需执行所有Unicode-ishly(您使用Encode :: encode和Encode :: decode for),你应该没问题.)

  1. Am I doing it right code-wise (‘course not)?
  2. Am I doing it right filesystem-wise?

是的,除了我认为你应该更多地关注错误案例.如果您的输入无法在区域设置字符集中表示,该怎么办?如果可以,但结果不是您的操作系统或文件系统中的有效文件名?

要解决此问题,您应该进行两次或三次更改:

>您应该为Encode :: encode提供一个明确的第三个参数,以指定它应该如何处理不可编码的字符. (默认行为是用替换字符替换它们,例如?对于US-ASCII;这可能不是您想要的.)
>您应该检查mkdir的返回值.
>您可能希望使用make_path的error选项,并检查生成的arrayref;或者,您可能希望将make_path包装在eval块中.

点赞