Man*_*o D 5 command-line regular-expression rename
我在 Ubuntu 上使用以下命令rename(安装了sudo apt-get rename)来重命名在正则表达式中具有给定字符的所有文件:
find . -execdir rename 's/[^A-Za-z0-9_.@+,#!?:&%~\(\)\[\]\/ \-]/?/g' * {} \;
Run Code Online (Sandbox Code Playgroud)
这工作得很好,所有其他字符都更改为?. 现在我想包括法语字符àèìòù等等。所以我添加À-ÿ到我的正则表达式:
find . -execdir rename 's/[^A-Za-zÀ-ÿ0-9_.@+,#!?:&%~\(\)\[\]\/ \-]/?/g' * {} \;
Run Code Online (Sandbox Code Playgroud)
但是不知何故,这些文件没有被重命名,并且在运行此命令后它们似乎已损坏,À-ÿ因为我无法再删除它们。
将它们包含在重命名正则表达式中的正确方法是什么?
假设这些文件名以 UTF-8 编码,请使用:
find . -depth -execdir rename -n '
utf8::decode$_ or die "cannot decode $_\n";
s{[^\w.\@+,#!?:&%~()\[\]/ -]}{?}gs;
utf8::encode$_;
' {} +
Run Code Online (Sandbox Code Playgroud)
(删除-n快乐时)。
请注意,某些 BSD 实现find的文件名没有前缀 with ./,-execdir因此如果文件名以-. 使用 的变体rename,您应该能够通过更改rename -n为来解决它rename -n --(这不适用于所有其他 perlrename变体)。
在现代版本perl,\w(对于字字符),任何字母(任何字母文字,不只是拉丁),或下划线加上其他连接器标点符号chararcters加上统一标志(因此,例如,包括组合重音符后面的字符e在的分解形式é)。
如果您想更加严格,而不是\w,您可以使用\p{latin}\p{mark}0-9_仅包含拉丁字母中的字母(而不是西里尔字母、希腊字母……)、组合变音符号(尽管不限于通常与拉丁字母一起使用的那些),以及只有印度-阿拉伯十进制数字(而不是其他类型的数字)和下划线(而不是其他连接符标点字符)。
如果您不使用utf8::decode,perl将假定字符以 iso8859-1 单字节字符集编码(例如 where 0xc3 0xa9( 的预组合形式的 UTF-8 编码é是Ã ©)。
或者,您可以使用zsh(它将根据区域设置的编码解码字符(请参阅 )的输出locale charmap):
autoload zmv # best in ~/.zshrc
zmv -n '(**/)(*)(#qD)' '$1${2//[^][:alnum:]_.@+,#!?:&%~()[\/ -]/?}'
Run Code Online (Sandbox Code Playgroud)
在您的语言环境中没有形成有效字符的任何字节序列中的每个字节也将被转换为 a ?(rename上面会因cannot decode错误而死亡)。
它[[:alnum:]]使用您的语言环境alnum类别,因此不太可能包含其他 Unicode 连接器标点符号或标记字符。
在两者perl和zsh(但通常不是在其他工具中)中,范围[a-zÀ-ÿ]都基于字符的代码点。举例来说azÀÿ都是\u0061\u007A\u00C0\u00FF如此,该范围将匹配abcdefghijklmnopqrstuvwxyzÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ在该范围内的代码点(包括非字母字符,而不是在拉丁字母的所有字符或法语等所使用的字符œ)。在perl,你想也需要添加一个use utf8能够使用的UTF-8编码À,并ÿ在Perl代码。