使用Perl和rename
,我想更改为小写或大写,除文件名中的最后N个字符外。
例如,如果N是10并且需要大写,那么
foo_1_bar_2-abcdef.txt
应该成为FOO_1_BAR_2-abcdef.txt
。
我尝试了rename "y/a-z{.10}$/A-Z/" *
之类的内容,但y
运算符似乎不想{.10}
。
答案 0 :(得分:2)
我更倾向于使用\U
转义序列而不是uc
以及替换的表达式模式。前瞻性前瞻也消除了重新组合字符串
use strict;
use warnings 'all';
use feature 'say';
my $s = join '', 'a' .. 'z';
$s =~ s/(.+)(?=.{10})/\U$1/;
say $s;
ABCDEFGHIJKLMNOPqrstuvwxyz
但是,如果您的文件名始终是给定的形式,即您总是希望在连字符之前将部分大写,那么您应该通过上下文而不是计算字符数来保持不变
use strict;
use warnings 'all';
use feature 'say';
my $s = 'foo_1_bar_2-abcdef.txt';
$s =~ s/^([^-]+)/\U$1/;
say $s;
FOO_1_BAR_2-abcdef.txt
答案 1 :(得分:1)
我认为这是因为你不了解y///
正在做什么。
这是基于字符的替换,所以你说a-z中的'transliterate' - > A-Z
在这种情况下,{.10}
只是另一组要替换的字符(但左侧没有匹配。
更清楚地了解发生的事情:
y/a-z{.10}$/A-Zlmnopq/;
在你的字符串上会成功:
FOO_n_BAR_2-ABCDEFmTXT
因为'0'和'1'映射到字符。
要做你想做的事,你可以像这样解决它:
s/(.*)(.{10})/uc ($1).$2/e;
E.g:
#!/usr/bin/env perl
use strict;
use warnings;
while (<DATA>) {
s/(.*)(.{10})/uc ($1).$2/e;
print;
}
__DATA__
foo_1_bar_2-abcdef.txt
(上面你不需要行结束锚,因为.*
正则表达式是贪婪的。)
这会输出:
FOO_1_BAR_2-abcdef.txt
虽然您可能会发现更好/更适合处理分隔符锚定(例如-text
,因为这似乎是您的目标。(我猜):
s/(.*-)/uc ($1)/e;
答案 2 :(得分:1)
除s///
解决方案外,这似乎也是substr
的一项轻松工作:
my $n = 10; # number of chars left untouched at the end
substr $s, 0, -$n, lc substr $s, 0, -$n;