【发布时间】:2014-06-01 17:06:42
【问题描述】:
如何将o 与e 和e 与o 交换?
我刚刚尝试过,但我认为这不是一个好方法。有没有更好的办法?
my $str = 'Absolute force';
$str =~ s/e/___eee___/g;
$str =~ s/o/e/g;
$str =~ s/___eee___/o/g;
输出:Abseluto ferco
【问题讨论】:
如何将o 与e 和e 与o 交换?
我刚刚尝试过,但我认为这不是一个好方法。有没有更好的办法?
my $str = 'Absolute force';
$str =~ s/e/___eee___/g;
$str =~ s/o/e/g;
$str =~ s/___eee___/o/g;
输出:Abseluto ferco
【问题讨论】:
$str =~ y/oe/eo/;
例如
$ echo "Absolute force" | perl -pe 'y/oe/eo/'
Abseluto ferco
【讨论】:
正如已经说过的,这样做的方法是transliteration operator
tr/SEARCHLIST/REPLACEMENTLIST/cdsr
y/SEARCHLIST/REPLACEMENTLIST/cdsr将在搜索列表中找到的所有字符转译为替换列表中的相应字符。它返回替换或删除的字符数。如果没有通过
=~或!~运算符指定字符串,则将转写$_字符串。
但是,我想赞扬您创造性地使用正则表达式。您的解决方案有效,尽管占位符字符串 _ee_ 就足够了。
tr 只是帮助你进行字符替换,所以我想快速教你如何利用正则表达式进行更复杂的批量替换。基本上,您只需使用/e 标签来执行 RHS 中的代码。以下内容也将完成您的目标:
my $str = 'Absolute force';
$str =~ s/([eo])/$1 eq 'e' ? 'o' : 'e'/eg;
print $str;
输出:
Abseluto ferco
请注意 LHS(左侧)如何匹配 o 和 e,而 RHS(右侧)会进行测试以查看哪个匹配并返回相反的替换。
现在,有一个要替换的单词列表很常见,因此只需构建 from/to 值的散列然后动态构建正则表达式就很方便。以下是这样做的:
my $str = 'Hello, foo. How about baz? Never forget bar.';
my %words = (
foo => 'bar',
bar => 'baz',
baz => 'foo',
);
my $wordlist_re = '(?:' . join('|', map quotemeta, keys %words) . ')';
$str =~ s/\b($wordlist_re)\b/$words{$1}/eg;
输出:
Hello, bar. How about foo? Never forget baz.
上面的内容也适用于您的e 和o 案例,但可能有点过头了。请注意我如何使用 quotemeta 来转义键,以防它们包含正则表达式特殊字符。我还特意在$wordlist_re 中围绕它们使用了一个非捕获组,以便可以将变量放入任何正则表达式并按需要运行。然后我将捕获组放在s/// 中,因为能够查看正则表达式中捕获的内容而不必回溯到插值变量的值非常重要。
【讨论】:
tr/// 运算符是最好的。但是,如果您想使用 s/// 运算符(处理的不仅仅是单个字母替换),您可以编写
$ echo 'Absolute force' | perl -pe 's/(e)|o/$1 ? "o" : "e"/eg'
Abseluto ferco
捕获括号避免了@Miller 的答案中多余的$1 eq 'e' 测试。
【讨论】:
来自man sed:
y/source/dest/ 将源中出现的模式空间中的字符音译为dest中的对应字符。
tr 命令也可以做到这一点:
$ echo "Absolute force" | tr 'oe' 'eo'
Abseluto ferco
【讨论】:
perldoc perlre(或man perlre)可能比man sed 更合适。