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”并运行,以此测试Perl环境是否正常工作。
可以使用以下代码实现:
print "Hello, world!
";
若使用Perl 5.10或更高版本,可尝试:
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.
";
该代码提示用户输入半径,将输入存储在变量
$radius
中,计算圆的周长,并处理半径为负数的情况,最后输出结果。
5、编写一个Perl程序,接收用户输入的圆的半径。如果用户输入的数字小于零,程序报告的圆的周长将为零,而不是负数。
#!/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 "请输入第一个数字:";
$num1 = <STDIN>;
chomp($num1);
print "请输入第二个数字:";
$num2 = <STDIN>;
chomp($num2);
$result = $num1 * $num2;
print "两数相乘的结果是:$result
";
7、编写一个程序,提示用户输入一个字符串和一个数字(分别在不同的输入行),然后将该字符串按照数字所指定的次数,逐行打印输出。(提示:使用乘法运算符)
以下是使用 Python 实现的代码示例:
string = input("请输入一个字符串:")
number = int(input("请输入一个数字:"))
print((string + "
") * number)
上述代码首先通过
input
函数获取用户输入的字符串和数字,然后使用乘法运算符将字符串重复指定次数,并逐行打印输出。
8、编写一个名为 total 的子例程,它返回一个数字列表的总和。该子例程不应执行任何输入输出操作,应仅处理其参数并将一个值返回给调用者。请在一个示例程序中测试这个子例程,示例程序中第一组数字 1、3、5、7、9 的总和应该是 25,并且程序还应允许用户输入一些数字,计算这些输入数字的总和并输出结果。
以下是实现
total
子例程的代码:
sub total {
my $sum;
foreach (@_) {
$sum += $_;
}
$sum;
}
为避免可能返回未定义值,可将
$sum
初始化为
0
:
sub total {
my $sum = 0;
foreach (@_) {
$sum += $_;
}
return $sum;
}
9、编写一个程序来计算 1 到 1000 的数字之和。
由于不清楚上一题子程序具体内容无法直接使用,这里给出 Python 示例代码:
result = sum(range(1, 1001))
print(f'The numbers from 1 to 1000 add up to {result}.')
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)”);
以下是实现该功能的代码:首先需要一个计算总和的子程序
total
,然后编写计算平均值的子程序
average
,最后编写
above_average
子程序。示例代码如下:
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!
以下是实现该功能的代码:
use 5.010;
greet( 'Fred' );
greet( 'Barney' );
sub greet {
state $last_name;
my $name = shift;
print "Hi $name! ";
if( defined $last_name ) {
print "$last_name is also here!
";
} else {
print "You are the first one here!
";
}
$last_name = $name;
}
12、修改之前的程序,让它告知每个新到来的人之前已经问候过的所有人的名字。执行以下语句序列: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:"; # 提示用户输入
chomp(my @lines = <STDIN>); # 读取输入并去除换行符
print "1234567890" x 6, "
"; # 打印标尺线
foreach (@lines) {
printf "%20s
", $_; # 右对齐打印每个字符串
}
在上述代码中,首先提示用户输入一系列字符串,然后使用
<STDIN>
读取输入并存储在
@lines
数组中,同时使用
chomp
去除换行符。接着打印标尺线,最后使用
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
", $_;
}
该代码先让用户输入列宽,接着输入一些行,然后根据输入的列宽生成长度合适的标尺线,最后将每行字符串按指定列宽右对齐输出。此外,也可以使用
printf "%*s
", $width, $_;
这种方式来输出,避免使用字符串插值时可能出现的问题。
15、编写一个程序,要求用户输入一个名字,并报告对应的姓氏。对于输入’fred’,输出’flintstone’;输入’barney’,输出’rubble’;输入’wilma’,输出’flintstone’。若输入的名字不在上述范围内,提示未找到对应的姓氏。
以下是一个用 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 "未找到对应的姓氏。
";
}
这个程序首先定义了一个哈希表
%name_map
,用于存储名字和姓氏的映射关系。然后,它提示用户输入一个名字,并将输入的名字转换为小写,以便不区分大小写。最后,它检查输入的名字是否在哈希表中,如果存在,则输出对应的姓氏;否则,输出未找到对应的姓氏的提示信息。
16、编写一个程序,逐行读取一系列单词,直到输入结束,然后打印出每个单词出现的次数摘要。如果输入的单词是 fred、barney、fred、dino、wilma、fred(每行一个单词),输出应显示 fred 出现了 3 次。额外加分项:按代码点顺序对输出的摘要单词进行排序。
以下是实现该功能的 Perl 代码:
my %count;
while (<STDIN>) {
chomp;
$count{$_}++;
}
foreach my $word (sort keys %count) {
print "$word was seen $count{$word} times.
";
}
这段代码首先使用
while
循环逐行读取标准输入,使用
chomp
去除每行末尾的换行符,然后使用哈希表
%count
统计每个单词的出现次数。最后,使用
sort
函数对哈希表的键进行排序,并打印出每个单词及其出现次数。
17、编写一个程序,打印输入中提到“fred”的每一行(对于其他行不做处理)。如果输入字符串是“Fred”、“frederick”或“Alfred”,程序是否会匹配?创建一个包含几行提及“fred flintstone”及其朋友的小文本文件,然后将该文件作为此程序的输入,程序会有怎样的输出?
要编写这样的程序,可将模式改为
/[fF]red/
。正则表达式区分大小写,原模式不匹配“Fred”,但修改后的模式可以。“frederick”和“Alfred”能匹配,因为它们都包含“fred”。
以下是示例代码:
while (<>) {
if (/[fF]red/) {
print;
}
}
将包含“fred flintstone”及其朋友的文本内容保存为文件,运行此程序并将该文件作为输入,程序会打印出包含“fred”的行。
18、修改之前的程序,使其也能匹配“Fred”。如果输入字符串是“Fred”、“frederick”或“Alfred”,现在能匹配上吗?(假设需要通过正则表达式来实现匹配,并将这些名字添加到文本文件中进行匹配测试)
正则表达式区分大小写,原本不匹配“Fred”。
修改模式为
/[fF]red/
可匹配。
“frederick”和“Alfred”能匹配,因为它们包含“fred”。
若要只匹配整个单词,后续会介绍相关功能。
19、编写一个程序,打印出每行中包含一个首字母大写但并非全大写的单词的行。该程序能匹配 Fred,但不匹配 fred 或 FRED 吗?
可以将之前程序中使用的模式更改为
/[A-Z][a-z]+/
来实现此功能。该模式能匹配
Fred
,但不匹配
fred
或
FRED
,因为它要求单词首字母为大写,后续字母为小写。
20、附加题:编写一个程序,打印出任何同时提及了“wilma”和“fred”的输入行。
可使用正则表达式和编程语言来实现该程序。以 Python 为例,代码如下:
while True:
try:
line = input()
if 'wilma' in line.lower() and 'fred' in line.lower():
print(line)
except EOFError:
break
上述代码通过循环不断读取输入行,将每行转换为小写后检查是否同时包含“wilma”和“fred”,若包含则打印该行。
21、使用模式测试程序,创建一个模式,用于匹配任何以字母 a 结尾的单词(这里的单词是指符合 w 定义的单词)。该模式是否能匹配 wilma 但不匹配 barney?是否能匹配字符串 ‘Mrs. Wilma Flintstone’ 中的单词?是否能匹配字符串 ‘wilma&fred’ 中的单词?
可使用模式
/w*a/
来匹配以字母
a
结尾的单词。此模式能匹配
wilma
但不匹配
barney
,能匹配
'Mrs. Wilma Flintstone'
中的
Wilma
,也能匹配
'wilma&fred'
中的
wilma
。
22、创建一个模式,该模式能匹配当前 $what 变量中内容的三个连续副本。也就是说,如果 $what 是 fred,你的模式应匹配 fredfredfred;如果 $what 是 fred|barney,你的模式应匹配 fredfredbarney、barneyfredfred、barneybarneybarney 等多种变体。(提示:你应该在模式测试程序的开头使用类似 my $what = ‘fred|barney’; 的语句来设置 $what。)
可使用模式
/$what{3}/
来匹配
$what
的三个连续副本。在 Perl 代码中,示例如下:
my $what = 'fred|barney';
my $string = '待匹配的具体字符串';
if ($string =~ /($what){3}/) {
print "匹配成功
";
}
其中
$string
是待匹配的字符串。
23、编写一个程序,对文本文件进行修改复制。在复制文件中,每个字符串 Fred(不区分大小写)应替换为 Larry。(例如,Manfred Mann 应变为 ManLarry Mann。)输入文件名应在命令行中给出(不要询问用户),输出文件名应为对应的以 .out 结尾的文件名。
以下是实现该功能的完整 Perl 程序代码:
use strict;
use warnings;
# 检查命令行参数
if (@ARGV != 1) {
die "Usage: perl script.pl <input_file>
";
}
my $in = $ARGV[0];
my $out = $in;
$out =~ s/.[^.]*$/.out/ if $out =~ /./; # 如果有扩展名,替换为 .out
$out .= ".out" if $out !~ /./; # 如果没有扩展名,追加 .out
# 打开输入文件
open my $in_fh, '<', $in or die "Can't open '$in': $!";
# 打开输出文件
open my $out_fh, '>', $out or die "Can't write '$out': $!";
# 逐行读取输入文件,进行替换并写入输出文件
while (my $line = <$in_fh>) {
$line =~ s/Fred/Larry/gi; # 不区分大小写的全局替换
print $out_fh $line;
}
# 关闭文件句柄
close $in_fh;
close $out_fh;
该程序首先检查命令行参数是否正确,获取输入文件名。然后将输入文件名处理为对应的以
.out
结尾的输出文件名。接着打开输入和输出文件句柄,逐行读取输入文件,使用
s/Fred/Larry/gi
进行不区分大小写的全局替换,将
Fred
替换为
Larry
,最后将处理后的行写入输出文件。处理完成后关闭文件句柄。
24、编写一个程序,将版权声明行(如 ## Copyright (C) 20XX by Yours Truly)添加到指定的练习答案文件中,该声明行应紧跟在“shebang”行之后。你需要对文件进行“原地”编辑,并保留备份。假设程序调用时,待编辑的文件名已经在命令行中给出。
以下是实现该功能的 Perl 程序:
@ARGV = @ARGV;
$^I = ".bak"; # 制作备份
while (<>) {
if (/^#!/) { # 是否为 shebang 行?
$_ .= "## Copyright (C) 20XX by Yours Truly
";
}
print;
}
上述代码首先通过
@ARGV
获取命令行传入的文件名,然后设置文件备份后缀为
.bak
。接着使用
while (<>)
逐行读取文件内容,当遇到以
#!
开头的 shebang 行时,在该行后面添加版权声明行,最后将处理后的内容输出,实现原地编辑文件并保留备份。
25、修改一个程序,使其不编辑已经包含版权声明行的文件。提示:正在读取的文件名存储在 $ARGV 中。
以下是实现该功能的代码:
首先,为避免重复添加版权信息,对文件进行两次遍历。第一次,创建一个哈希
%do_these
,键为文件名,值设为
1
:
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"; # 制作备份
while (<>) {
if (/A#!/) { # 是否为 shebang 行
$_ .= "## Copyright (c) 20XX by Yours Truly
";
}
print;
}