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”的 Perl 程序,以此测试系统的 Perl 环境是否可以正常工作。

可以通过以下几种方式编写和运行“Hello, world”程序:

普通

print

方式:

perl
print "Hello, world!
";

v5.10 及以后版本使用

say



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

命令行运行方式:

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


Windows 下:

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

v5.10 及以后版本使用

-E

开关:

bash
$ perl -E 'use v5.10; say "Hello, World"'

将程序保存为文件后运行:

在 Linux 等系统:

bash
$ ./my_program

在 Windows 系统:

cmd
C:> perl my_program

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


#!/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.
";

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、编写一个程序,让用户输入圆的半径,若用户输入的数字小于零,程序报告的圆周长将为零而不是负数,若输入的数字大于等于零,则正常计算圆周长并报告。


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

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


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

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

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


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. "
";
}

8、编写一个程序,逐行读取字符串列表,直到输入结束,然后按逆序输出该列表。如果输入来自键盘,在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程序员会更喜欢第二种方式,只要他们不需要保留这些行的列表以供后续使用。

9、编写一个程序,逐行读取字符串列表,直到输入结束。然后,它应按代码点顺序打印这些字符串。也就是说,如果你输入字符串 fred、barney、wilma、betty,输出应该显示 barney betty fred wilma。请实现输出中的所有字符串显示在一行上和显示在不同行上这两种样式。

以下是两种实现方式:

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

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

若要将输出显示在不同行上,代码如下:

perl
print sort <STDIN>;

10、编写一个程序来计算 1 到 1000 的数字之和

由于不清楚上一题子程序的具体情况,原答案依赖上一题子程序无法独立存在,所以为 DELETE

11、编写一个名为 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(@_);  # from earlier exercise
    $sum / $count;
}

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

其中

average

子程序用于计算平均值,

above_average

子程序用于返回高于平均值的数字列表。

12、编写一个名为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' );

13、修改上一个程序,告知每个新到来的人之前所有被问候过的人的名字。执行以下语句序列: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


使用 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;
}

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

以下是一个用 Perl 编写的实现该功能的程序:


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

将上述代码保存为一个文件(例如

tac.pl

),并赋予执行权限:


chmod +x tac.pl

然后可以使用以下命令运行程序:


./tac.pl fred barney betty

15、编写一个程序,要求用户在不同行输入一系列字符串,将每个字符串打印在右对齐、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
", $_;
}

16、修改之前的程序,让用户选择列宽,这样输入 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
", $_;
}

代码解释:

首先,程序会提示用户输入列宽,使用

chomp

去除用户输入的换行符。

接着,提示用户输入一些行,直到用户按下

Ctrl - D

(或

Ctrl - Z

)。

然后,通过

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

生成标尺行,标尺行的长度至少与所需列宽一样长。

最后,使用

foreach

循环遍历用户输入的每一行,并使用

printf

函数将每行字符串显示在指定列宽处。

17、编写一个程序,要求用户输入一个名字,并输出对应的姓氏。已知名字和姓氏的对应关系如下:名字为 fred 时,姓氏为 flintstone;名字为 barney 时,姓氏为 rubble;名字为 wilma 时,姓氏为 flintstone。

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


#!/usr/bin/perl
use strict;
use warnings;

# 定义名字和姓氏的映射表
my %name_map = ( 
    'fred'   => 'flintstone', 
    'barney' => 'rubble', 
    'wilma'  => 'flintstone'
);

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

# 将输入转换为小写以支持不区分大小写的匹配
$given_name = lc $given_name;

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

这个程序首先定义了一个名字和姓氏的映射表,然后提示用户输入一个名字。接着,程序将输入的名字转换为小写,并检查它是否在映射表中。如果存在,程序将输出对应的姓氏;否则,程序将输出未找到对应的姓氏的消息。

18、编写一个程序,读取一系列单词(每行一个单词)直到输入结束,然后打印出每个单词出现的次数摘要。因此,如果输入的单词是 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.
";
}

19、编写一个程序,列出 %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)";
}

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

可以将程序中使用的模式改为

/[fF]red/

,也可以尝试

/(f|F)red/


/fred|Fred/

,但字符类更高效。更改模式后,输入

"Fred"


"frederick"


"Alfred"

都能匹配。

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

可以使用模式

/$what){3}/

来匹配

$what

的三个连续副本。在程序中实现如下:


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

22、编写一个程序,制作文本文件的修改副本。在副本中,每个字符串 Fred(不区分大小写)应替换为 Larry。(因此 Manfred Mann 应变为 ManLarry Mann。)输入文件名应在命令行中给出(不要询问用户!),输出文件名应为对应的以 .out 结尾的文件名。


my $in = $ARGV[0];
if (! defined $in) {
    die "Usage: $0 filename";
}
my $out = $in;
$out =~ s/(.w+)?$/.out/;
if (! open $in_fh, '<', $in ) {
    die "Can't open '$in': $!";
}
if (! open $out_fh, '>', $out ) {
    die "Can't write '$out': $!";
}
while (<$in_fh>) {
    s/Fred/Larry/gi;
    print $out_fh $_;
}

23、修改一个程序,使其不编辑已经包含版权声明行的文件。提示:由钻石操作符读取的文件名存储在 $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 (<>) {
    ...
}

24、编写一个程序,该程序会反复要求用户猜测一个1到100之间的秘密数字,直到用户猜对为止。程序应使用神奇公式 int(1 + rand 100) 随机选择一个数字。当用户猜错时,程序应回复“太高了”或“太低了”。如果用户输入“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!
";
    }
}

25、编写一个程序,识别命令行中指定的最旧的文件,并报告其年龄(以天为单位)。如果命令行中未提及任何文件(即文件列表为空),程序会怎样?

如果列表为空,程序会报错并输出提示信息:

“No file names supplied!”

,因为没有文件可供检查,也就不存在最旧的文件。

© 版权声明

相关文章

暂无评论

none
暂无评论...