Perl编程实践:调试、日期计算与文件操作

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

26、编写一个 Perl 程序,程序会生成一个 1 到 100 之间的随机整数作为秘密数字。要求程序在运行过程中可以打印额外的调试信息,例如它选择的秘密数字。并且可以关闭此功能,当关闭时程序不会发出警告。如果你使用的是 Perl 5.10 或更高版本,请使用 // 运算符。否则,请使用条件运算符。


下面是给定的【文本内容】:

使用 Perl 5.10 及以后版本:

```perl
use 5.010;
my $Debug = $ENV{DEBUG} // 1;
my $secret = int(1 + rand 100);
print "Don't tell anyone, but the secret number is $secret.
" if $Debug;

不使用 Perl 5.10 新特性:


my $Debug = defined $ENV{DEBUG} ? $ENV{DEBUG} : 1;
my $secret = int(1 + rand 100);
print "Don't tell anyone, but the secret number is $secret.
" if $Debug;

27、编写一个使用 DateTime 模块的程序,计算当前时间与在命令行输入的年、月、日所表示的日期之间的时间间隔,例如执行

perl duration.pl 1960 9 30

会输出

50 years, 8 months, and 20 days


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


use DateTime;
# 获取当前时间
my $now = DateTime->now;
# 从命令行获取输入的日期
my $then = DateTime->new(
    year => $ARGV[0],
    month => $ARGV[1],
    day => $ARGV[2],
);
# 检查输入的日期是否在未来
if ($now < $then) {
    die "You entered a date in the future!
";
}
# 计算时间间隔
my $duration = $now - $then;
# 获取年、月、日的时间间隔
my @units = $duration->in_units(qw(year month day));
# 输出结果
printf "%d years, %d months, and %d days
", @units;

将上述代码保存为

duration.pl

,然后在命令行运行

perl duration.pl 年 月 日

即可计算时间间隔。

28、编写一个程序,使用堆叠文件测试运算符列出命令行中指定的所有可读、可写且归当前用户所有的文件。

在 Perl 5.10 及以后版本中,示例代码如下:


use 5.010;
print "Looking for my files that are readable and writable
";
die "No files specified!
" unless @ARGV;
foreach my $file ( @ARGV ) {
    print "$file is readable and writable
" if( -w -r -o $file );
}

该代码首先提示正在查找可读且可写的文件,接着检查命令行是否指定了文件,若未指定则终止程序。然后遍历命令行指定的每个文件,使用堆叠文件测试运算符

-w -r -o

检查文件是否可写、可读且归当前用户所有,若满足条件则打印文件名。

29、修改程序以包含所有文件,而不仅仅是不以点开头的文件。

若要修改程序以包含所有文件,可移除跳过点文件的代码:

在第一个程序里,移除

## now includes .*

相关注释以及

next if /A./;

这行代码;

在第二个程序中,去掉

next if /A./;

这行代码;

在第三个程序中,去掉

next if $name =~ /^./;

这行代码。

这样程序就能包含所有文件,而不只是不以点开头的文件。

30、编写一个程序,其功能类似于

mv

命令,将第一个命令行参数指定的文件重命名为第二个命令行参数指定的名称。(无需处理

mv

命令的选项或额外参数。)要考虑目标参数可能是一个目录的情况;如果是目录,则在新目录中使用原文件的基本名称。

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


use File::Basename;
use File::Spec;

my ($source, $dest) = @ARGV;

if (-d $dest) {
    my $basename = basename $source;
    $dest = File::Spec->catfile($dest, $basename);
}

rename $source, $dest or die "Can't rename '$source' to '$dest': $!";

该程序首先引入

File::Basename


File::Spec

模块,接着获取命令行参数。若目标参数是目录,会提取源文件的基本名称并将其添加到目标目录路径后。最后进行重命名操作,若失败则输出错误信息。

31、如果你的操作系统支持,编写一个类似

ln

命令的程序,从第一个命令行参数创建一个硬链接到第二个命令行参数。(你不需要处理

ln

的选项或更多参数。)如果你的系统没有硬链接,只需打印一条消息,说明如果支持该操作你会执行什么操作。

程序编写说明

在编写该程序时,需根据系统是否支持硬链接进行不同的处理:


在支持硬链接的系统上

,可使用系统调用函数创建硬链接。


在不支持硬链接的系统上

,应输出相应的提示信息。

以下是以 Python 为例的示例代码:


import os
import sys

if len(sys.argv) != 3:
    print("用法: python script.py <源文件> <目标硬链接>")
    sys.exit(1)

source = sys.argv[1]
link_name = sys.argv[2]

try:
    os.link(source, link_name)
    print(f"成功创建硬链接 {link_name} 指向 {source}")
except AttributeError:
    print(f"此系统不支持硬链接。若支持,将创建硬链接 {link_name} 指向 {source}")
except FileNotFoundError:
    print(f"源文件 {source} 未找到。")
except FileExistsError:
    print(f"目标硬链接 {link_name} 已存在。")
except PermissionError:
    print("没有足够的权限创建硬链接。")

32、编写一个程序,将以下哈希数据按姓氏进行不区分大小写的字母顺序排序。当姓氏相同时,再按名字(同样不区分大小写)排序。所有姓氏相同的人应该分组在一起。不要修改数据。名字的大小写应与这里显示的一致。哈希数据为:my %last_name = qw{ fred flintstone Wilma Flintstone Barney Rubble betty rubble Bamm – Bamm Rubble PEBBLES FLINTSTONE };

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


my %last_name = qw{ fred flintstone Wilma Flintstone Barney Rubble betty rubble Bamm - Bamm Rubble PEBBLES FLINTSTONE };
my @sorted_names = sort { lc($last_name{$a}) cmp lc($last_name{$b}) or lc($a) cmp lc($b) } keys %last_name;
foreach my $name (@sorted_names) {
    print "$name $last_name{$name}
";
}

这段代码首先定义了一个哈希

%last_name

,然后使用

sort

函数对哈希的键进行排序。排序规则是先按姓氏的小写形式进行字母顺序排序,如果姓氏相同,则按名字的小写形式排序。最后,遍历排序后的键并打印出名字和姓氏。

33、编写一个程序,在给定的字符串中查找给定子字符串的所有出现位置,并打印出这些位置。例如,给定输入字符串 “This is a test.” 和子字符串 “is”,程序应报告位置 2 和 5。如果子字符串是 “a”,则应报告 8。如果子字符串是 “t”,程序会报告哪些位置?

程序会报告位置

0


10


13

因为在字符串

"This is a test."

中:

字母

"t"

首次出现在第 1 个字符(索引为

0

),

再次出现在第 11 个字符(索引为

10

),

最后出现在第 14 个字符(索引为

13

)。

34、使用

given

和智能匹配,编写一个程序,报告你在命令行中指定的数字的所有约数(除 1 和该数字本身)。例如,对于数字 99,程序应报告它能被 3、9、11 和 33 整除。如果该数字是质数(没有约数),则报告该数字是质数。如果命令行参数不是数字,报告错误且不尝试计算约数。仅使用智能匹配,而不使用

if

结构和普通匹配。

以下是满足需求的 Perl 程序:


use 5.010;
say "Checking the number <$ARGV[0]>";
given( $ARGV[0] ) {
    when( ! /Ad+/ ) { say "Not a number!" }
    my @divisors = divisors( $_ );
    my @empty;
    when( @divisors ~~ @empty ) { say "Number is prime" }
    default { say "$_ is divisible by @divisors" }
}
sub divisors {
    my $number = shift;
    my @divisors = ();
    foreach my $divisor ( 2 .. $number/2 ) {
        push @divisors, $divisor unless $number % $divisor;
    }
    return @divisors;
}

此程序首先检查命令行参数是否为数字。若不是,输出错误信息;若是,计算其约数。若约数为空,表明该数字是质数;否则,输出该数字的所有约数。

35、编写一个程序,输入一个数字,程序要报告该数字是奇数还是偶数,该数字是否为质数(除了1和它本身没有其他约数),以及它是否能被你喜欢的数字(假设喜欢的数字为42)整除,仅使用智能匹配。

以下是修改后的程序:


use 5.010;
say "Checking the number <$ARGV[0]>";
my $favorite = 42;
given( $ARGV[0] ) {
    when( ! /Ad+/ ) { say "Not a number!" }
    my @divisors = divisors( $ARGV[0] );
    when( @divisors ~~ 2 ) { # 2 is in @divisors
        say "$_ is even";
        continue;
    }
    when( !( @divisors ~~ 2 ) ) { # 2 isn't in @divisors
        say "$_ is odd";
        continue;
    }
    when( @divisors ~~ $favorite ) { 
        say "$_ is divisible by my favorite number";
        continue;
    }
    when( $favorite ) { # $_ ~~ $favorite
        say "$_ is my favorite number";
        continue;
    }
    my @empty;
    when( @divisors ~~ @empty ) { 
        say "Number is prime"
    }
    default { 
        say "$_ is divisible by @divisors"
    }
}
sub divisors {
    my $number = shift;
    my @divisors = ();
    foreach my $divisor ( 2 .. ($ARGV[0]/2 + 1) ) {
        push @divisors, $divisor unless $number % $divisor;
    }
    return @divisors;
}

36、编写一个程序,将当前工作目录更改到某个特定(硬编码)的目录,例如系统的根目录,然后执行

ls -l

命令以获取该目录的长格式目录列表。(如果使用非 Unix 系统,请使用自己系统的命令来获取详细的目录列表)

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


chdir '/' or die "Can't chdir to root directory: $!";
exec 'ls', '-l' or die "Can't exec ls: $!";

第一行将当前工作目录更改为根目录,第二行使用多参数

exec

函数执行

ls -l

命令并将结果输出到标准输出。

37、(仅适用于Unix系统)编写一个无限循环程序,该程序能捕获信号,报告捕获到了哪个信号以及之前看到该信号的次数。如果捕获到INT信号则退出程序。若可以使用命令行的kill命令,可按如下方式发送信号:$ kill -USR1 12345;若不能使用命令行的kill命令,编写另一个程序来向其发送信号,也许可以使用Perl单行命令:$ perl -e ‘kill HUP => 12345’。

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


use 5.010;

sub my_hup_handler {
    state $n;
    say 'Caught HUP: ', ++$n
}

sub my_usr1_handler {
    state $n;
    say 'Caught USR1: ', ++$n
}

sub my_usr2_handler {
    state $n;
    say 'Caught USR2: ', ++$n
}

sub my_int_handler {
    say 'Caught INT. Exiting.';
    exit
}

say "I am $$";

foreach my $signal ( qw(int hup usr1 usr2) ) {
    $SIG{ uc $signal } = "my_${signal}_handler";
}

while(1) {
    sleep 1;
}

要发送信号,可以使用如下命令:


$ kill -HUP 进程ID

$ perl -e 'kill HUP => 进程ID'
$ perl -e 'kill USR2 => 进程ID'

其中,进程ID是运行该程序时显示的进程号。

38、使用 Perl 语言输出“Hello, world!”,请给出相应代码。

以下几种方式都可以实现:

普通

print

语句:

perl
print "Hello, world!
";

使用

say

(Perl 5.10 或更高版本):

perl
use 5.010;
say "Hello, world!";

从命令行运行:

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

使用

-l

开关从命令行运行:

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

39、编写一个 Perl 程序,计算半径为 12.5 的圆的周长并输出。

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


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

my $radius = 12.5;
my $circumference = 2 * 3.14159 * $radius;

print "半径为 12.5 的圆的周长是: $circumference
";

将上述代码保存为一个

.pl

文件,例如

circle_circumference.pl

,然后在终端中运行

perl circle_circumference.pl

即可看到结果。

40、编写一个 Perl 程序,让用户输入圆的半径,然后计算并输出该圆的周长。

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


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

print "请输入圆的半径: ";
my $radius = <STDIN>;
chomp($radius);

my $circumference = 2 * 3.14159 * $radius;
print "该圆的周长是: $circumference
";

在这个程序中,首先提示用户输入圆的半径,然后读取用户输入并去除换行符,接着使用圆周长公式

2 * π * 半径

计算周长,最后输出计算结果。需要注意的是,这里

π

取值为 3.14159。

41、编写一个Perl程序,计算半径为12.5的圆的周长,并输出结果。

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


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

my $radius = 12.5;
my $circumference = 2 * 3.14159 * $radius;
print "半径为12.5的圆的周长是: $circumference
";

将上述代码保存为一个

.pl

文件,例如

circle_circumference.pl

,然后在终端中运行

perl circle_circumference.pl

即可看到计算结果。

42、编写一个Perl程序,提示用户输入圆的半径,然后计算并输出该圆的周长。

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


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

# 提示用户输入圆的半径
print "请输入圆的半径: ";
my $radius = <STDIN>;
chomp($radius);

# 计算圆的周长
my $circumference = 2 * 3.14159 * $radius;

# 输出圆的周长
print "该圆的周长是: $circumference
";

该程序首先提示用户输入圆的半径,接着读取用户输入并去除换行符,然后根据圆的周长公式

2 * π * 半径

计算周长,最后输出计算结果。

43、编写一个Perl程序,提示用户输入圆的半径,计算并输出该圆的周长。如果用户输入的半径为负数,输出的周长应为0。

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


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

print "请输入圆的半径: ";
my $radius = <STDIN>;
chomp($radius);

if ($radius < 0) {
    $radius = 0;
}

my $circumference = 2 * 3.14159 * $radius;
print "圆的周长是: $circumference
";

该程序首先提示用户输入圆的半径,然后检查输入的半径是否为负数,如果是则将半径设为0,最后计算并输出圆的周长。

44、编写一个Perl程序,提示用户输入两个数字,将这两个数字相乘,并输出结果。

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


#!/usr/bin/perl
print "请输入第一个数字: ";
chomp(my $num1 = <STDIN>);
print "请输入第二个数字: ";
chomp(my $num2 = <STDIN>);
my $result = $num1 * $num2;
print "两数相乘的结果是: $result
";

上述程序会提示用户输入两个数字,将它们相乘,并输出结果。

45、编写一个Perl程序,提示用户输入一个字符串和一个数字,将该字符串重复指定的次数,并输出结果,要求字符串在不同行显示。

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


#!/usr/bin/perl
use strict;
use warnings;
print "请输入一个字符串: ";
chomp(my $string = <STDIN>);
print "请输入一个数字: ";
chomp(my $number = <STDIN>);
for (my $i = 0; $i < $number; $i++) {
    print $string . "
";
}

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

for

循环将字符串重复指定的次数,并在每次循环中输出字符串并换行。

46、编写一个Perl程序,提示用户输入多行文本,然后将这些行反转并输出。

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


#!/usr/bin/perl

print "请输入多行文本,输入结束后按Ctrl+D(Windows下按Ctrl+Z):
";

my @lines = ();

while (my $line = <STDIN>) {
    chomp($line);
    push @lines, $line;
}

my @reversed_lines = reverse @lines;

foreach my $reversed_line (@reversed_lines) {
    print $reversed_line . "
";
}

该程序首先提示用户输入多行文本,通过循环读取用户输入的每一行,去除行尾的换行符后存储在数组中。接着使用

reverse

函数反转数组元素顺序,最后遍历反转后的数组并输出每一行。

47、编写程序,读取用户输入的行,将这些行排序后输出,要求输出可以在一行或多行

以下是一个使用Python实现的示例代码:


lines = []
while True:
    line = input()
    if not line:
        break
    lines.append(line)
lines.sort()
for line in lines:
    print(line)

这段代码会持续读取用户输入的行,直到用户输入一个空行。然后对这些行进行排序并逐行输出。如果想将结果输出在一行,可以将最后一行改为

print(' '.join(lines))

© 版权声明

相关文章

暂无评论

none
暂无评论...