我一直在寻找有关如何在不使用内置reverse
函数的情况下在Perl中反转字符串的线索,并且遇到了以下用于反转$ str的代码。
print +($str =~ /./g)[-$_] for (1 .. $#{[$str =~ /./g]} + 1);
我试图理解它是如何工作的,并将上面的代码扩展为类似的东西。
for (1 .. $#{[$str =~ /./g]} + 1) {
$rev_str_1 = ($str =~ /./g)[-$_];
print $rev_str_1;
}
上面的代码片段也可以正常工作。但是,当我在for
循环中添加任何打印以了解字符串操作是如何工作时,问题就出现了。
for (1 .. $#{[$str =~ /./g]} + 1) {
$rev_str_1 = ($str =~ /./g)[-$_];
print "\nin loop now ";
print $rev_str_1;
}
对于stressed
的输入字符串,以下是上述代码的输出
in loop now d
in loop now e
in loop now s
in loop now s
in loop now e
in loop now r
in loop now t
in loop now s
似乎整个字符串反转发生在这部分($str =~ /./g)[-$_]
中,但我试图理解为什么当我添加额外的打印时它不起作用。感谢任何指针。
答案 0 :(得分:5)
你假设在打印之前字符串是反转的,但是程序只是以相反的顺序一次打印字符串中的所有字符
以下是它的工作原理
它基于表达式$str =~ /./g
,它使用全局正则表达式匹配,匹配任何单个字符的模式。在列表上下文中,它将字符串中的所有字符作为列表返回。请注意,没有.
模式修饰符的点/s
与换行符不匹配。这是一个错误,但在这种情况下可能并不重要
此表达式
$#{ [ $str =~ /./g ] } + 1
使用$str
在[ $str =~ /./g ]
中创建一个匿名的字符数组。然后使用$#
获取数组最后一个元素的索引,并添加1以获取字符总数(因为索引从零开始)。因此,循环正在$_
执行,范围为1 $str
中的字符数。这是不必要的模糊,应该写成1 .. length($str)
,除了上面提到的换行字符的特殊情况
循环体使用($str =~ /./g)[-$_]
,它以与以前相同的方式再次将$str
拆分为字符,然后使用Perl中的负索引引用相对于结束数组或列表。因此$str
中的最后一个字符位于索引-1处,第二个字符位于索引-2处,依此类推。再次,这是不必要的奥术;表达式完全等同于substr($str, -$_, 1)
,除了正则表达式版本忽略换行字符
一次打印一个字符会导致$str
反向打印
可能更容易理解字符串是否被拆分为实数组,并且反向字符串被累积到缓冲区中,就像这样
my $reverse = '';
my @str = $str =~ /./sg;
for ( 1 .. @str ) {
$reverse .= $str[-$_];
}
print $reverse, "\n";
或者,如上所述使用length
和substr
,这相当于
my $reverse = '';
$reverse .= substr($str, -$_, 1) for 1 .. length($str);
print $reverse, "\n";