我想在Perl中用另一个字符串替换一个字符串;两者的长度相同。我想替换所有出现的字符串(不区分大小写),但我希望保留字母的大小写。因此,如果第一个字母是大写字母,则替换后的第一个字母也将是大写字母。
例如,如果我想用“bar”替换“foo”,那么我想要那个
foo ==> bar
Foo ==> Bar
FOO ==> BAR
在Perl中有一种简单的方法吗?
答案 0 :(得分:13)
这可能就是你所追求的:
How do I substitute case insensitively on the LHS while preserving case on the RHS?
这几乎是直接从以上链接复制的:
sub preserve_case($$) {
my ($old, $new) = @_;
my $mask = uc $old ^ $old;
uc $new | $mask .
substr($mask, -1) x (length($new) - length($old))
}
my $string;
$string = "this is a Foo case";
$string =~ s/(Foo)/preserve_case($1, "bar")/egi;
print "$string\n";
# this is a Bar case
$string = "this is a foo case";
$string =~ s/(Foo)/preserve_case($1, "bar")/egi;
print "$string\n";
# this is a bar case
$string = "this is a FOO case";
$string =~ s/(Foo)/preserve_case($1, "bar")/egi;
print "$string\n";
# this is a BAR case
答案 1 :(得分:13)
perldoc perlfaq6
提供了一些见解:
如何在保留RHS案例的同时对LHS不区分大小写?
这是Larry Rosler的一个可爱的Perlish解决方案。它利用了 ASCII字符串上按位
xor
的属性。$_= "this is a TEsT case"; $old = 'test'; $new = 'success'; s{(\Q$old\E)} { uc $new | (uc $1 ^ $1) . (uc(substr $1, -1) ^ substr $1, -1) x (length($new) - length $1) }egi; print; # 'this is a SUcCESS case'
在这里它是一个子程序,模仿上述:
sub preserve_case { my ($old, $new) = @_; my $mask = uc $old ^ $old; uc $new | $mask . substr($mask, -1) x (length($new) - length($old)) } $string = "this is a TEsT case"; $string =~ s/(test)/preserve_case($1, "success")/egi; print "$string\n";
打印:
this is a SUcCESS case
所以你可以像这样使用preserve_case()
子程序。只是不要指望Unicode奇迹:)
s[\b(abc)\b][preserve_case($1,'xyz')]ei ;
答案 2 :(得分:6)
$text =~ s/\b(?:(Abc)|abc)\b/ $1 ? 'Xyz' : 'xyz' /eg;
如果实际列表较长,则可以使用查找表。
my %translations = (
'Abc' => 'Xyz', 'abc' => 'xyz',
'Def' => 'Ghi', 'def' => 'ghi',
'Jkl' => 'Mno', 'jkl' => 'mno',
);
my $alt_pat = join '|', map quotemeta, keys(%translations);
$text =~ s/\b($alt_pat)\b/$translations{$1}/g;
但是这仍然会留下一些可以通过派生小写版本来删除的重复。
my %translations = (
'Abc' => 'Xyz',
'Def' => 'Ghi',
'Jkl' => 'Mno',
);
%translations = ( ( map lc, %translations ), %translations );
my $alt_pat = join '|', map quotemeta, keys(%translations);
$text =~ s/\b($alt_pat)\b/$translations{$1}/g;
答案 3 :(得分:5)
这是一个解决方案,将“将一个字符串更改为与另一个字符串的大小写相匹配”的概念转化为函数,并调用该函数来构建替换。
sub matchcap
{
my ($s,$r) = @_;
return $s eq ucfirst($s) ? ucfirst($r) : lcfirst($r);
}
s/\b(Abc|abc)\b/matchcap($1,'xyz')/ge;
答案 4 :(得分:3)
有点黑客,使用实验代码扩展正则表达式:
$text =~ s/\b([Aa])(?{ $n=chr(ord($^N)+23) })bc/${n}yz/
首先,将字母A与([Aa])
匹配。以下(?{...})
包含任意代码,其中$^N
包含最近捕获的子组的文本。 23是A和X之间ASCII码的差异(大写和小写),因此$n
包含字母X,其大小写与相应的A相同。
(这不应被视为编写此类代码的认可,而是作为此实验性正则表达式的一个有趣示例。)
答案 5 :(得分:3)
这是一个“半perlish”解决方案,适用于任意regexps 和 Unicode数据:
sub adjust_case {
my ($text, $case) = @_;
$case .= substr($case, -1) x (length($text) - length($case));
$_ = [ split // ] for $text, $case;
return join "", map {
$case->[$_] =~ /\p{Upper}/ ? uc $text->[$_] :
$case->[$_] =~ /\p{Lower}/ ? lc $text->[$_] : $text->[$_]
} 0 .. $#$text;
}
my $regexp = qr/\b(abc\w*)\b/i;
my $replace = "Xyzzy";
s/$regexp/adjust_case $replace, ${^MATCH}/egp;
答案 6 :(得分:2)
你可以这样做:
my %trans = (
'Abc' => Xyz,
'abc' => xyz,
);
$text =~s/\b(Abc|abc)\b/$trans{$1}/ge;
答案 7 :(得分:1)
你知道每个字符串的长度是相同的,所以基本上你可以:
index = Pos(string, oldString)
for i = index to index + strlen(oldString)
if (oldString[i] >= 'a') && (oldString[i] <= 'z'')
string[i] = ToLower(newString[i])
else
string[i] = ToUpper(newString[i])0x20
答案 8 :(得分:0)
逐个字符检查。如果字符的ASCII值以大写ASCII值表示,请替换为大写,否则为小写。
答案 9 :(得分:0)
这是一个巧妙的技巧,在替换结果中使用非破坏性音译(在Perl 5.14中可用)。
use 5.014;
$string =~ s/\b(f)(o)(o)\b/ ($1 =~ tr{fF}{bB}r) . ($2 =~ tr{oO}{aA}r) . ($3 =~ tr{oO}{rR}r) /egi;
如果连续的字母组具有相同的替换,您甚至可以缩短它,例如
# foo ==> see, FoO ==> SeE, etc.
$string =~ s/\b(foo)\b/ $1 =~ tr{fFoO}{sSeE}r /egi;