我要同时标准化几个文件的名称,因此我编写了一个正则表达式perl-rename
:
perl-rename 'y/A-Z/a-z/; s/ã|á|â/a/g; s/é|ê/e/g; s/í/i/g; s/õ|ó/o/g; s/ú/u/g; s/ç/c/g; s/(?<=\d-)*\s/_/g; s/_+/_/g; s/(?<=\d)_/-/' *
它完全按照预期工作:
2024-12-01 certidão de matrícula -> 2024-12-01-certidao_de_matricula
然而,我认为它可以简化一点,所以我想到了这一点:
perl-rename 'y/A-Z/a-z/; y/ãáâéêíõóúç/aaaeeioouc/; s/(?<=\d-)*\s/_/g; s/_+/_/g; s/(?<=\d)_/-/' *
但结果却不符合我的预期。例如:
2024-12-01 certidão de matrícula -> 2024-12-01-certidaao_de_matraccula
为什么第二个命令不起作用,因为它应该直接音译每个重音字符?我甚至无法理解结果。提前致谢。
发生这种情况是因为 Perl 不知道它应该将文件名视为 UTF-8。相反,它会查看单个字节,因此您会得到部分替换和重复。例如,考虑以下情况:
这里,输入为
\xc3\xa4:\xc3\xb6:\xc3\xa4
,而y/ä/x/
被视为y/\xc3\xa4/x/
(右侧x
隐式重复)。结果是,当两个字节被单独替换时,UTF-8ä
变为xx
,而ö
当仅替换第一个字节时,UTF-8 会崩溃。该
s///
命令有效,因为它会查找要替换的整个字符串,因此将其解释为一个字符还是两个字节并不重要。您可以通过添加
use utf8
或-Mutf8
告诉 Perl 源是采用 UTF-8 格式,以及-C
告诉它 stdin/stdout 是采用 UTF-8 格式的选项来解决这个问题。使用重命名脚本,您可能无法使用
-C
,因此请使用PERL_UNICODE
环境变量,例如 withexport PERL_UNICODE=AS
(用于参数和 Stdin/out),并将其包含use utf8
在重命名命令中并希望它有效。