Perl编程练习题与解答汇总

内容分享2天前发布
0 0 0

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

1、当方括号内的数字37出现在一道练习题文本开头时,它代表什么意思?

这个数字是对完成该特定练习题预计所需分钟数的大致估计。不过这个估计比较粗略,实际完成时间可能是预计时间的一半,也可能两倍都不止。

2、输入一个程序,使其输出“Hello, world”并运行。你可以随意命名该程序。

以下几种方式可实现“Hello, world”程序:

编写文件:

在文件中写入

perl
print "Hello, world!
";


若使用 v5.10 或更高版本,可使用

perl
use v5.10;
say "Hello, world!";

命令行运行:

使用

-e

开关指定程序,如

bash
$ perl -e 'print "Hello, World
"'


使用

-l

开关自动添加换行符,如

bash
$ perl -le 'print "Hello, World"'


Windows 系统命令行使用双引号在外,如

cmd
C:> perl -le "print 'Hello, World'"


也可使用广义引号,如

cmd
C:> perl -le "print q(Hello, World)"


v5.10 及更高版本使用

-E

开关启用新特性以使用

say

,如

cmd
C:> perl -E'say "Hello, world!"'

3、编写一个程序,计算半径为 12.5 的圆的周长。圆的周长是 2π 乘以半径(约为 2 乘以 3.141592654)。

以下是两种实现该功能的 Perl 程序示例:

示例一:


#!/usr/bin/perl
use warnings;
$pi = 3.141592654;
$circ = 2 * $pi * 12.5;
print "The circumference of a circle of radius 12.5 is $circ.
";

示例二:


#!/usr/bin/perl
use utf8;
use warnings;
$π = 3.141592654;
$circ = 2 * $π * 12.5;
print "The circumference of a circle of radius 12.5 is $circ.
";

4、编写一个程序,提示用户输入圆的半径,然后根据输入的半径计算并输出该圆的周长。例如,如果用户输入的半径为 12.5,程序应能计算并输出该圆的周长。


#!/usr/bin/perl
use warnings;
$pi = 3.141592654;
print "What is the radius? ";
chomp($radius = <STDIN>);
$circ = 2 * $pi * $radius;
print "The circumference of a circle of radius $radius is $circ.
";

5、编写一个程序,提示用户输入两个数字(分别在不同的输入行),并输出这两个数字相乘的结果。

以下是实现该功能的程序示例:


print "Enter first number: ";
chomp($one = <STDIN>);
print "Enter second number: ";
chomp($two = <STDIN>);
$result = $one * $two;
print "The result is $result.
";

6、编写一个程序,提示用户输入一个字符串和一个数字(分别在不同的输入行),并将该字符串按照数字指定的次数打印在不同的行上。(提示:使用 x 运算符)。如果用户输入“fred”和“3”,输出应该是三行,每行都显示“fred”。如果用户输入“fred”和“299792”,可能会有大量输出。

以下是实现该功能的程序:


print "Enter a string: ";
$str = <STDIN>;
print "Enter a number of times: ";
chomp($num = <STDIN>);
$result = $str x $num;
print "The result is:$result";

该程序首先提示用户输入一个字符串,然后提示输入一个数字。使用

x

运算符将字符串重复指定的次数,并将结果存储在

$result

变量中。最后,将结果打印输出。

不过原答案中说能确保每个字符串都在单独的行上存在问题,因为输入的字符串本身可能没有换行符,若要保证每行一个字符串,可修改代码如下:


print "Enter a string: ";
$str = <STDIN>;
chomp($str); # 去除字符串末尾的换行符
print "Enter a number of times: ";
chomp($num = <STDIN>);
for (my $i = 0; $i < $num; $i++) {
    print $str. "
";
}

修改后的代码使用循环每次打印字符串并添加换行符,确保每个字符串都在单独的行上。

7、编写一个程序,逐行读取字符串列表,直到输入结束,然后按逆序输出该列表。如果输入来自键盘,在Unix系统中可能需要按Ctrl – D,在Windows系统中可能需要按Ctrl+Z来表示输入结束。

以下是两种实现方式:

方式一:


print "Enter some lines, then press Ctrl - D:
";
@lines = <STDIN>;
@reverse_lines = reverse @lines;
print @reverse_lines;

方式二(更简洁):


print "Enter some lines, then press Ctrl - D:
";
print reverse <STDIN>;

大多数Perl程序员会更喜欢第二种方式,只要他们不需要保留这些行的列表以供后续使用。

8、编写一个程序,逐行读取字符串列表,直到输入结束。然后按码点顺序打印这些字符串。也就是说,如果你输入字符串 fred、barney、wilma、betty,输出应该是 barney betty fred wilma。输出的所有字符串是在一行上还是分行显示?你能让输出以这两种样式呈现吗?

以下是两种实现方式:

若要将输出显示在一行上,代码为:

perl
chomp(@lines = <STDIN>); @sorted = sort @lines; print "@sorted
";

若要分行显示输出,代码为:

perl
print sort <STDIN>;

9、编写一个名为 above_average 的子程序,它接受一个数字列表,并返回那些高于平均值(均值)的数字。(提示:编写另一个子程序,通过将总和除以项目数量来计算平均值。)在以下测试程序中测试你的子程序:my @fred = above_average(1..10); print “@fred is @fred

”; print “(Should be 6 7 8 9 10)

“; my @barney = above_average(100, 1..10); print “@barney is @barney

“; print “(Should be just 100)

“;

以下是实现代码:


sub average {
    if (@_ == 0) { return }
    my $count = @_;
    my $sum = total(@_); # 假设 total 子程序已在之前定义
    $sum / $count;
}

sub above_average {
    my $average = average(@_);
    my @list;
    foreach my $element (@_) {
        if ($element > $average) {
            push @list, $element;
        }
    }
    @list;
}

其中,

average

子程序用于计算平均值,

above_average

子程序用于返回高于平均值的数字列表。注意,代码中使用了

total

子程序,需要确保该子程序已经在之前定义。

10、编写一个名为 greet 的子程序,在欢迎你指定的人时,告诉他们上一个被问候的人的名字。例如执行 greet( “Fred” ); greet( “Barney” ); 这组语句应该输出:Hi Fred! You are the first one here! Hi Barney! Fred is also here!

以下是实现该功能的代码:


sub greet {
    state $last_person;
    my $name = shift;
    print "Hi $name! ";
    if( defined $last_person ) {
        print "$last_person is also here!
";
    } else {
        print "You are the first one here!
";
    }
    $last_person = $name;
}

greet( 'Fred' );
greet( 'Barney' );

11、修改程序,实现当调用 greet 函数时,告知每个新到来的人之前所有被问候过的人的名字。运行如下语句:greet( “Fred” ); greet( “Barney” ); greet( “Wilma” ); greet( “Betty” ); 程序应输出:Hi Fred! You are the first one here! Hi Barney! I’ve seen: Fred Hi Wilma! I’ve seen: Fred Barney Hi Betty! I’ve seen: Fred Barney Wilma

以下是实现该功能的代码:


use v5.10;

greet( 'Fred' );
greet( 'Barney' );
greet( 'Wilma' );
greet( 'Betty' );

sub greet {
    state @names;
    my $name = shift;
    print "Hi $name! ";
    if( @names ) {
        print "I've seen: @names
";
    } else {
        print "You are the first one here!
";
    }
    push @names, $name;
}

12、编写一个程序,功能类似于 cat 命令,但将输出行的顺序反转(有些系统有类似的名为 tac 的实用工具)。如果以 ./tac fred barney betty 运行该程序,输出应该是文件 betty 从最后一行到第一行的内容,接着是 barney 的内容(同样从最后一行到第一行),最后是 fred 的内容(也是从最后一行到第一行)。(如果程序名为 tac,调用时一定要使用 ./ ,以免调用系统自带的实用工具)

以下是一个用 Perl 编写的

tac

程序示例:


#!/usr/bin/perl

foreach my $file (reverse @ARGV) {
    open(my $fh, '<', $file) or die "无法打开文件 $file: $!";
    my @lines = <$fh>;
    close($fh);
    print reverse @lines;
}

13、编写一个程序,要求用户在不同行输入一系列字符串,将每个字符串打印在一个右对齐、20 个字符宽的列中。为确保输出列格式正确,同时打印一行数字作为“标尺线”(仅用于调试)。注意不要误使用 19 个字符宽的列。例如,输入 hello 和 good – bye 时,输出应类似这样:123456789012345678901234567890123456789012345678901234567890

hello

good – bye

以下是实现该功能的 Perl 代码:


print "Enter some lines, then press Ctrl - D:
"; # or Ctrl - Z
chomp(my @lines = <STDIN>);
print "1234567890" x 7, "12345
"; # ruler line to column 75
foreach (@lines) {
    printf "%20s
", $_;
}

代码解释:

首先提示用户输入一些行,然后按 Ctrl – D(或 Ctrl – Z)结束输入。

使用

chomp

函数去除输入行末尾的换行符,并将输入的所有行存储在数组

@lines

中。

打印标尺线,这里重复“1234567890”七次并追加“12345”,以达到 75 列的标尺效果。

通过

foreach

循环遍历

@lines

数组,使用

printf

函数以

%20s

格式打印每个字符串,实现右对齐且宽度为 20 个字符的输出效果。

14、修改之前的程序,让用户选择列宽,例如依次输入 30、hello、good – bye(每行一个输入),能将字符串输出在第 30 列。额外加分项:当选定的列宽较大时,让标尺行更长。

以下是实现该功能的代码:


print "What column width would you like? ";
chomp(my $width = <STDIN>);
print "Enter some lines, then press Ctrl - D:
";
# or Ctrl - Z
chomp(my @lines = <STDIN>);
print "1234567890" x (($width + 9) / 10), "
";
# ruler line as needed
foreach (@lines) {
    printf "%${width}s
", $_;
}

代码解释:


获取列宽

:程序首先提示用户输入所需的列宽,并将用户输入存储在变量

$width

中,使用

chomp

去除换行符。


获取输入行

:接着提示用户输入一些行,按 Ctrl – D(或 Ctrl – Z)结束输入,将输入的行存储在数组

@lines

中,同样使用

chomp

去除换行符。


生成标尺行

:根据用户输入的列宽,使用

print "1234567890" x (($width + 9) / 10), "
"

生成标尺行,确保标尺行至少和所需宽度一样长。


输出字符串

:遍历输入的每一行,使用

printf "%${width}s
", $_

将字符串输出在指定的列宽位置。

关于变量插值:

使用

${width}

进行变量插值,需要使用花括号将变量名与后面的字符隔离开,避免插值错误的变量。若忘记使用花括号,也可以用

'%' . $width . "
"

得到相同的格式字符串。

注意事项:

使用

chomp

去除

$width

中的换行符很重要,否则生成的格式字符串会包含换行符,导致输出不符合预期。

15、编写一个程序,向用户询问名字并报告对应的姓氏。已知名字和姓氏的对应关系如下:fred 对应 flintstone,barney 对应 rubble,wilma 对应 flintstone。

以下是一个满足需求的 Perl 程序示例:


# 创建一个哈希表来存储名字和姓氏的对应关系
my %name_mapping = (
    'fred'  => 'flintstone',
    'barney' => 'rubble',
    'wilma' => 'flintstone'
);

# 提示用户输入名字
print "请输入一个名字: ";
my $given_name = <STDIN>;
chomp $given_name; # 去除换行符

# 将输入的名字转换为小写,以便匹配哈希表中的键
$given_name = lc $given_name;

# 检查输入的名字是否在哈希表中
if (exists $name_mapping{$given_name}) {
    print "对应的姓氏是: $name_mapping{$given_name}
";
} else {
    print "未找到对应的姓氏。
";
}

这个程序首先创建了一个哈希表

%name_mapping

,用于存储名字和姓氏的对应关系。然后提示用户输入一个名字,去除输入中的换行符,并将其转换为小写。接着检查输入的名字是否在哈希表中,如果存在则输出对应的姓氏,否则输出未找到的提示信息。

16、编写一个程序,读取一系列单词(每行一个单词)直到输入结束,然后打印出每个单词出现的次数总结。(提示:记住当一个未定义的值被当作数字使用时,Perl 会自动将其转换为 0。回顾之前记录累计总数的练习可能会有帮助。)所以,如果输入的单词是 fred、barney、fred、dino、wilma、fred(都在不同的行上),输出应该告诉我们 fred 出现了 3 次。额外加分项:按代码点顺序对输出中的总结单词进行排序。

以下是实现该功能的 Perl 代码:


my(@words, %count, $word);
chomp(@words = <STDIN>);
foreach $word (@words) {
    $count{$word} += 1;
}
foreach $word (sort keys %count) {
    print "$word was seen $count{$word} times.
";
}


代码解释:


首先声明所需变量,使用

<STDIN>

读取所有输入行到

@words

数组并去除换行符。接着使用

foreach

循环遍历

@words

数组,对于每个单词,将其在

%count

哈希表中的计数加 1。最后,再次使用

foreach

循环遍历

%count

哈希表的键(按代码点顺序排序),并打印每个单词及其出现次数。

17、编写一个程序,列出 %ENV 中的所有键和值。以 ASCII 码顺序将结果打印成两列。若想获得额外加分,可使输出的两列垂直对齐。可以使用 length 函数来确定第一列的宽度。程序运行后,尝试设置一些新的环境变量,并确保它们显示在输出中。

以下是实现该功能的代码:


use v5.10;
$ENV{ZERO} = 0;
$ENV{EMPTY} = '';
$ENV{UNDEFINED} = undef;
my $longest = 0;
foreach my $key ( keys %ENV ) {
    my $key_length = length( $key );
    $longest = $key_length if $key_length > $longest;
}
foreach my $key ( sort keys %ENV ) {
    printf "%-${longest}s %s
", $key, $ENV{$key} // "(undefined value)";
}

这段代码首先设置了几个环境变量,然后找出所有键中最长的长度,最后按 ASCII 码顺序遍历所有键,使用

printf

函数将键和值以两列形式输出,并使两列垂直对齐。对于未定义的值,会显示

(undefined value)

18、编写一个程序,打印输入中提到“fred”的每一行,而对其他行不做处理。如果输入字符串是“Fred”、“frederick”或“Alfred”,是否会匹配?创建一个包含几行提及“fred flintstone”及其朋友的小文本文件,然后将该文件作为此程序的输入。

此问题要求编写程序筛选出包含“fred”的行,对于输入“Fred”、“frederick”、“Alfred”,只有“fred”会匹配。

需创建含“fred flintstone”相关内容的文本文件用于测试。

可使用正则表达式编写程序,示例代码如下:


while (<>) {
    if (/fred/) {
        print;
    }
}

将上述代码保存为

.pl

文件,运行时将创建的文本文件作为输入,如:


perl script.pl input.txt

19、有一个程序,需要修改该程序,使其能匹配“Fred”。若输入字符串是“Fred”、“frederick”或“Alfred”,修改程序后能否匹配这几个字符串?(需将包含这些名字的行添加到文本文件中)

将程序的模式改为

/[fF]red/

,也可以尝试

/(f|F)red/


/fred|Fred/

,但字符类效率更高。修改后,输入“Fred”、“frederick”、“Alfred”都能匹配,因为:

“Fred”直接匹配

“frederick”和“Alfred”中包含“fred”

20、编写一个程序,打印出任何同时提及“wilma”和“fred”的输入行。

可通过正则表达式和条件判断来实现。思路是读取输入行,检查是否同时包含“wilma”和“fred”,若包含则打印该行。以下是一个 Python 示例代码:


while True:
    try:
        line = input()
        if 'wilma' in line.lower() and 'fred' in line.lower():
            print(line)
    except EOFError:
        break

21、创建一个模式,使其能匹配当前 $what 变量中内容的三个连续副本。也就是说,如果 $what 是 fred,你的模式应匹配 fredfredfred。如果 $what 是 fred|barney,你的模式应匹配 fredfredbarney、barneyfredfred、barneybarneybarney 等多种组合。(提示:你应该在模式测试程序的开头使用类似 my $what = ‘fred|barney’; 的语句来设置 $what。)

可以使用以下代码实现:


my $what = 'fred|barney';
while( <STDIN> ) {
    chomp;
    if ( /($what){3}/ ) {
        print "Matches
";
    } else {
        print "Doesn't match
";
    }
}

这里使用了括号将

$what

括起来,然后使用

{3}

量词来匹配其内容的三个连续副本。

22、编写一个程序,修改已有程序,使其不编辑已经包含版权行的文件。提示:由钻石操作符读取的文件名存储在 $ARGV 中。


为了避免重复添加版权信息,需要对文件进行两次遍历。首先,使用哈希创建一个“集合”,其中键是文件名,值可随意(为方便使用 1):

```perl
my %do_these;
foreach (@ARGV) {
    $do_these{$_} = 1;
}

接着,检查文件并从待办列表中移除已经包含版权信息的文件。当前文件名存储在

$ARGV

中,可将其用作哈希键:


while (<>) {
    if (/A## Copyright/) {
        delete $do_these{$ARGV};
    }
}

最后,在重新确定

@ARGV

中的文件名列表后,执行与之前相同的程序:


@ARGV = sort keys %do_these;
$^I = ".bak"; # 制作备份
exit unless @ARGV; # 没有参数则从标准输入读取!

while (<>) {
    ...
}

23、编写一个程序,该程序会不断让用户猜测一个1到100之间的秘密数字,直到用户猜对为止。程序应使用公式 int(1 + rand 100) 随机选取这个秘密数字。当用户猜错时,程序应提示“Too high”或“Too low”。若用户输入“quit”“exit”或空行,程序应退出。当然,若用户猜对,程序也应退出。

以下是实现该功能的Perl代码:


my $secret = int(1 + rand 100);
while (1) {
    print "Please enter a guess from 1 to 100: ";
    chomp(my $guess = <STDIN>);
    if ($guess =~ /quit|exit|As*z/i) {
        print "Sorry you gave up. The number was $secret.
";
        last;
    } elsif ($guess < $secret) {
        print "Too low. Try again!
";
    } elsif ($guess == $secret) {
        print "That was it!
";
        last;
    } else {
        print "Too high. Try again!
";
    }
}
© 版权声明

相关文章

暂无评论

none
暂无评论...