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、当方括号内的数字2出现在练习题文本开头时,它意味着什么?

这个数字是对完成该特定练习题所需时间(分钟)的大致估计。

不过这只是粗略估算,实际完成时间可能是该数字的一半,也可能是两倍。

2、编写一个 Perl 程序,使其输出“Hello, world”并运行该程序,同时说明在命令行不创建文件运行该程序的方法。

程序代码如下:


print "Hello, world!
";

如果你使用的是 Perl 5.10 或更高版本,也可以尝试使用

say


use 5.010;
say "Hello, world!";

若想在命令行运行而不创建文件,可以使用

-e

开关指定程序:


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

还有

-l

开关能自动添加换行符:


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

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


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

4、编写一个程序,提示用户输入圆的半径,然后计算并输出该圆的周长。如果用户输入的半径为负数,则周长按 0 处理。例如,当用户输入的半径为 12.5 时,程序应能正确计算并输出相应的周长。


#!/usr/bin/perl -w
$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.
";

5、编写一个程序,让用户输入一个圆的半径,若用户输入的数字小于零,程序报告的圆周长将为零,而不是负数。


#!/usr/bin/perl -w
$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、编写一个程序,提示用户输入两个数字(在不同的输入行),并输出这两个数字相乘的结果。

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


print "请输入第一个数字: ";
chomp($num1 = <STDIN>);
print "请输入第二个数字: ";
chomp($num2 = <STDIN>);
$result = $num1 * $num2;
print "这两个数字的乘积是: $result
";

上述代码首先提示用户输入两个数字,使用

chomp

函数去除输入数字后的换行符,然后将这两个数字相乘得到结果,最后将结果输出。

7、编写一个程序,提示用户输入一个字符串和一个数字(分别在不同的输入行),并将该字符串按照数字指定的次数打印在不同的行上。(提示:使用 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

变量中。最后,程序打印出结果。注意,程序没有对输入的字符串进行

chomp

操作,这样可以确保每个重复的字符串都在单独的一行上。

8、编写一个程序,逐行读取一系列数字,直到输入结束,然后根据给定的姓名列表 [‘fred’, ‘betty’, ‘barney’, ‘dino’, ‘wilma’, ‘pebbles’, ‘bamm – bamm’],为每个输入的数字打印对应的人名。例如,如果输入的数字是1、2、4和2,输出的人名应该是fred、betty、dino和betty。

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


names = ['fred', 'betty', 'barney', 'dino', 'wilma', 'pebbles', 'bamm - bamm']
while True:
    try:
        num = int(input())
        if 1 <= num <= len(names):
            print(names[num - 1])
        else:
            print('输入的数字超出范围')
    except EOFError:
        break
    except ValueError:
        print('输入不是有效的数字')

此代码先定义了姓名列表,接着在循环里读取输入的数字,将其转换为整数并检查是否在有效范围内,若有效则打印对应人名,同时处理了输入结束和输入非有效数字的情况。

9、编写一个名为 total 的子程序,它返回一个数字列表的总和。该子程序不应执行任何输入/输出操作,只需处理其参数并将一个值返回给调用者。请编写该子程序,并在示例程序中进行测试,示例程序如下:my @fred = qw{ 1 3 5 7 9 }; my $fred_total = total(@fred); print “The total of @fred is $fred_total.
”; print “Enter some numbers on separate lines: “; my $user_total = total(

); print “The total of those numbers is $user_total.
”;

以下是实现

total

子程序的代码:


sub total {
    my $sum = 0;
    foreach (@_) {
        $sum += $_;
    }
    return $sum;
}

该子程序使用

$sum

来保存累加的总和,初始化为

0

。然后,

foreach

循环遍历参数列表(来自

@_

),使用

$_

作为控制变量,将每个元素累加到

$sum

中。最后返回

$sum

。这样即使参数列表为空,子程序也总是返回一个数字。

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

“;

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


sub total {
    my $sum = 0;
    foreach my $num (@_) {
        $sum += $num;
    }
    return $sum;
}

sub average {
    my @list = @_;
    if (!@list) {
        return undef;
    }
    my $sum = total(@list);
    my $count = scalar @list;
    return $sum / $count;
}

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

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)
";

上述代码中,

total

子程序用于计算列表中所有数字的总和,

average

子程序通过调用

total

计算平均值,

above_average

子程序调用

average

并找出高于平均值的数字。

11、编写一个名为 greet 的子程序,当你传入人名时,该子程序会向此人表示欢迎,并告知其上次打招呼的人的名字。例如,执行 greet( “Fred” ); greet( “Barney” ); 这两条语句时,程序应输出:Hi Fred! You are the first one here! Hi Barney! Fred is also here!

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


use 5.010;

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

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

上述代码定义了一个

greet

子程序,使用

state

关键字声明了一个持久变量

$last_name

来存储上一次打招呼的人的名字。每次调用

greet

子程序时,会根据

$last_name

是否有值来输出不同的欢迎信息,并更新

$last_name

的值。

12、修改程序,使得每次调用

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 5.010;
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;
}

13、编写一个程序,要求用户在不同行输入一系列字符串,将每个字符串右对齐打印在一个20字符宽的列中。为确保输出列位置正确,同时打印一行数字作为“标尺线”(这只是一个调试辅助手段)。要确保不会误使用19字符宽的列!例如,输入hello、good – bye,输出应类似如下形式:123456789012345678901234567890123456789012345678901234567890

hello

good – bye

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


print "Enter some lines, then press Ctrl - D:"; # 或 Ctrl - Z
chomp(my @lines = <STDIN>);
print "1234567890" x 6, "
"; # 打印标尺线
foreach (@lines) {
    printf "%20s
", $_;
}

代码解释:首先提示用户输入一些行,按Ctrl – D(或Ctrl – Z)结束输入。使用

chomp

函数去除输入行末尾的换行符。然后打印标尺线,这里重复了6次“1234567890”。最后,使用

foreach

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

printf

函数将每行右对齐打印在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
", $_;
}

该代码先让用户输入列宽,接着输入一些行,按Ctrl – D(或Ctrl – Z)结束输入。然后根据列宽生成合适的标尺线,最后将每行字符串按指定列宽右对齐输出。

15、编写一个程序,要求用户输入一个名字,并输出对应的姓氏。若输入的名字为 fred,输出 flintstone;若输入的名字为 barney,输出 rubble;若输入的名字为 wilma,输出 flintstone;若输入其他名字,输出未找到对应的姓氏。

以下是使用 Perl 语言实现该功能的代码:


use strict;
use warnings;

# 定义名字和姓氏的映射
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、编写一个程序,打印输入中提到“fred”的每一行(对于其他行不做处理)。如果输入字符串是“Fred”、“frederick”或“Alfred”,程序是否会匹配?创建一个包含几行提及“fred flintstone”及其朋友的小文本文件,然后将该文件作为此程序的输入。

要编写该程序,可将模式改为

/[fF]red/

。正则表达式区分大小写,原模式不匹配“Fred”,但新修改的模式可以。“frederick”和“Alfred”能匹配,因为它们都包含“fred”。

以下是示例代码:


while (<>) {
    if (/[fF]red/) {
        print;
    }
}

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

print_fred_lines.pl

),并创建一个包含“fred flintstone”及其朋友的文本文件(如

friends.txt

),然后在命令行运行:


perl print_fred_lines.pl friends.txt

17、修改之前的程序,使其也能匹配 Fred。若输入字符串是 Fred、frederick 或 Alfred,修改后的程序能否匹配这些字符串 ?(可将这些名字添加到文本文件中进行测试)

可以将之前程序使用的模式修改为

/[fF]red/

,也可以尝试

/(f|F)red/


/fred|Fred/

,但字符类更高效。

正则表达式区分大小写:

不匹配

Fred

能匹配

frederick


Alfred

,因为这两个字符串都包含四个字母的字符串

fred

仅匹配整个单词,使

frederick


Alfred

不匹配,这是后续会介绍的功能。

18、编写一个程序,打印出每行中包含一个首字母大写但并非全大写单词的行。该程序是否能匹配“Fred”,而不匹配“fred”和“FRED”?

可以通过将模式更改为

/[A-Z][a-z]+/

来实现此程序。该模式能匹配像“Fred”这样首字母大写且后续字母小写的单词,而不匹配全小写的“fred”和全大写的“FRED”。

19、使用模式测试程序,创建一个模式,用于匹配任何以字母 a 结尾的单词(这里的单词是指符合 w 定义的单词)。该模式是否能匹配 wilma 但不匹配 barney?是否能匹配 Mrs. Wilma Flintstone?wilma&fred 呢?

可使用模式

/w*a/

来匹配以字母

a

结尾的单词。

此模式能匹配

wilma

但不匹配

barney

,能匹配

Mrs. Wilma Flintstone

以及

wilma&fred

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

可以使用如下模式来实现:

qr/(?:$what){3}/

解释:

(?:$what)

是一个非捕获组,它将

$what

的内容作为一个整体;

{3}

表示前面的非捕获组要连续出现 3 次。

在 Perl 代码中可以这样使用:


my $what = 'fred|barney';
my $pattern = qr/(?:$what){3}/;

然后使用该模式进行匹配操作。

21、修改上一个程序,将每个 Fred 替换为 Wilma,将每个 Wilma 替换为 Fred。现在,像 fred&wilma 这样的输入在输出中应变为 Wilma&Fred。

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


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

# 检查是否提供了输入文件名
if (@ARGV != 1) {
    die "Usage: $0 <input_file>";
}

my $input_file = $ARGV[0];
my $output_file = $input_file . ".out";

open(my $in_fh, '<', $input_file) or die "Can't open $input_file: $!";
open(my $out_fh, '>', $output_file) or die "Can't open $output_file: $!";

while (my $line = <$in_fh>) {
    # 先将 Fred 替换为临时字符串,避免后续替换时产生冲突
    $line =~ s/(?i)Fred/TEMP_FRED/g;

    # 将 Wilma 替换为 Fred
    $line =~ s/(?i)Wilma/Fred/g;

    # 将临时字符串替换为 Wilma
    $line =~ s/TEMP_FRED/Wilma/g;

    print $out_fh $line;
}

close($in_fh);
close($out_fh);

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

replace_names.pl

),然后在命令行中运行:


perl replace_names.pl your_input_file.txt

程序会读取输入文件,将其中的 Fred 和 Wilma 进行互换,并将结果保存到以

.out

结尾的输出文件中。

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

以下是修改后的程序:

首先创建一个哈希

%do_these

,将命令行参数作为键存入,值设为

1

。接着遍历文件,若文件中包含以

## Copyright

开头的行,则从

%do_these

中删除该文件名对应的键。最后将

%do_these

中的键排序后重新赋值给

@ARGV

,再进行版权声明添加操作。

代码如下:


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

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

@ARGV = sort keys %do_these;
$^I = ".bak";

while (<>) {
    if (/^#!/) {
        $_ .= "## Copyright (c) 20XX by Yours Truly
";
    }
    print;
}

23、编写一个程序,该程序重复要求用户猜测一个1到100之间的秘密数字,直到用户猜对为止。程序应使用神奇公式 int(1 + rand 100) 随机选取数字。当用户猜错时,程序应回应“Too high”或“Too low”。如果用户输入“quit”或“exit”,或者输入空行,程序应退出。当然,如果用户猜对了,程序也应退出。

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


use 5.010;
my $secret = int(1 + rand 100);
while (1) {
    print "Please enter a guess from 1 to 100 (or 'quit'/'exit' to quit): ";
    chomp(my $guess = <STDIN>);
    if ($guess eq 'quit' || $guess eq 'exit' || $guess eq '') {
        last;
    }
    if ($guess =~ /^d+$/) {
        if ($guess == $secret) {
            print "Correct! You guessed the secret number.";
            last;
        } elsif ($guess > $secret) {
            print "Too high
";
        } else {
            print "Too low
";
        }
    } else {
        print "Invalid input. Please enter a valid number or 'quit'/'exit'.
";
    }
}

这个程序首先使用

int(1 + rand 100)

生成一个1到100之间的随机数作为秘密数字。然后进入一个无限循环,不断要求用户输入猜测的数字。如果用户输入“quit”、“exit”或空行,程序将退出循环。如果用户输入的是有效的数字,程序会将其与秘密数字进行比较,并给出“Too high”或“Too low”的提示,直到用户猜对或选择退出。

© 版权声明

相关文章

暂无评论

none
暂无评论...