我正在学习Perl工作,而我正在尝试使用一些基本程序。
我希望我的程序从STDIN获取一个字符串,并通过取最后一个字符并将其放在字符串的开头来修改它。
我在$str
中使用变量$str = <STDIN>
时收到错误。
这是我的代码:
my $str = "\0";
$str = <STDIN>;
sub last_to_first {
chomp($str);
pop($str);
print $str;
}
last_to_first;
执行:
Matrix :hi
Not an ARRAY reference at matrix.pl line 13, <STDIN> line 1.
答案 0 :(得分:9)
为什么您的方法不起作用
pop
keyword对字符串不起作用。 Perl中的字符串不会自动转换为字符数组,并且这些数组关键字仅适用于数组。
错误消息是不是ARRAY引用,因为pop
看到了标量变量。引用是Perl中的标量(这里的标量类似于对内存中实际数组的地址的引用)。 Perl版本中的pop
内置takes array references介于5.14和5.22之间。这是实验性的,but got removed in the (currently latest) 5.24。
从Perl 5.14开始,一个实验性功能允许pop采用标量表达式。该实验被认为是不成功的,并且从Perl 5.24开始被删除。
如何使其发挥作用
my $str = 'foo';
# turn it into an array
my @chars = split //, $str;
# remove the last char and put it at the front
unshift @chars, pop @chars;
# turn it back into a string
$str = join '', @chars;
print $str;
这会给你ofo
。
现在要将其用作子,您应该传递一个参数。否则你不需要子程序。
sub last_to_first {
my $str = shift;
my @chars = split //, $str;
unshift @chars, pop @chars;
$str = join '', @chars;
return $str;
}
您可以使用任何字符串参数调用该子。您应该执行chomp
以从子外部的STDIN中删除尾部换行符,因为切换字符不需要它。始终在尽可能小的单元中构建您的潜艇,以便于调试它们。一段代码应该只完成一个功能。
您也不需要使用\0
初始化字符串。事实上,这没有任何意义。
这是一个完整的程序。
use strict;
use warnings 'all';
my $str = <STDIN>;
chomp $str;
print last_to_first($str);
sub last_to_first {
my $str = shift;
my @chars = split //, $str;
unshift @chars, pop @chars;
$str = join '', @chars;
return $str;
}
测试您的计划
因为您的last_to_first
功能中现在有一个单元,所以您可以轻松实现单元测试。 Perl为此目的带来了Test::Simple和Test::More(以及其他工具)。因为这很简单,我们将使用Test :: Simple。
您加载它,告诉它您将要执行多少次测试,然后使用ok
函数。理想情况下,您可以将要测试的内容放入自己的模块中,但为了简单起见,我将在同一个程序中完成所有内容。
use strict;
use warnings 'all';
use Test::Simple tests => 3;
ok last_to_first('foo', 'ofo');
ok last_to_first('123', '321');
ok last_to_first('qqqqqq', 'qqqqqq');
sub last_to_first {
my $str = shift;
my @chars = split //, $str;
unshift @chars, pop @chars;
$str = join '', @chars;
return $str;
}
这将输出以下内容:
1..3
ok 1
ok 2
ok 3
使用prove
代替perl
运行它以获得更全面的输出。
重构
现在让我们改变last_to_first
的实现,使用regular expression substitution with s///
代替数组方法。
sub last_to_first {
my $str = shift;
$str =~ s/^(.+)(.)$/$2$1/;
return $str;
}
此代码使用与两个组()
的模式匹配。第一个字符串在字符串^
开头之后有很多字符,第二个字符串只有一个字符串,之后字符串结束$
。你可以查看here。这些群体最终会出现在$1
和$2
中,我们需要做的就是切换它们。
如果用测试替换程序中的函数,然后运行它,输出将是相同的。您刚刚重构了程序中的一个单元。
您也可以尝试使用此zdim's answer substr
方法进行此测试,您会看到测试仍然通过。
答案 1 :(得分:1)
核心函数pop
接受一个数组,并删除并返回它的最后一个元素。
要操纵字符串中的字符,您可以使用substr
,例如
use warnings;
use strict;
my $str = <STDIN>;
chomp($str);
my $last_char = substr $str, -1, 1, '';
my $new_str = $last_char . $str;
substr
的参数意味着:搜索变量$str
,偏移-1
(后面一个),查找长度为1
的子字符串,并替换为使用空字符串''
(从而删除它)。找到的子字符串(此处为最后一个字符)将被返回。请参阅上面链接的文档页面。
在最后一行中,使用.
运算符将返回的字符与剩余的字符串连接起来。
您可以在Perl functions by category
浏览按类别细分的功能列表。
Perl文档有很多好处,请环顾四周。
使用正则表达式经常操纵字符串。请参阅教程perlretut
,快速入门perlrequick
,快速参考perlreref
和完整参考perlre
。
您还可以将字符串拆分为字符数组并使用它。这在answer by simbabque中有详细显示,其中包含了很多很好的建议。
答案 2 :(得分:0)
这是用于数组变量的子串函数:
my @arrays = qw(jan feb mar);
last_to_first(@arrays);
sub last_to_first
{
my @lists = @_;
my $last = pop(@lists);
#print $last;
unshift @lists, $last;
print @lists;
}
这是用于标量变量的子串函数:
my $str = "";
$str = <STDIN>;
chomp ($str);
last_to_first($str);
sub last_to_first
{
my $chr = shift;
my $lastchar = substr($chr, -1);
print $lastchar;
}