" pop($ str)"中没有ARRAY参考错误;

时间:2016-08-10 09:27:39

标签: perl

我正在学习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.

3 个答案:

答案 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开始被删除。

如何使其发挥作用

您必须首先splitjoin字符串。

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::SimpleTest::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;
}