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

27、编写一个程序,其功能类似于
rm
命令,用于删除命令行中指定的所有文件。(无需处理
rm
命令的任何选项)

在 Perl 中,可以使用
unlink
操作符来实现此功能。示例代码如下:


#!/usr/bin/perl

# 获取命令行参数中的文件名列表
my @files = @ARGV;

# 使用unlink操作符删除文件
unlink @files or warn "无法删除文件: $!";

将上述代码保存为一个
.pl
文件,例如
rm_like.pl
,然后在命令行中运行
perl rm_like.pl filename1 filename2 ...
,即可删除指定的文件。

28、编写一个程序,其功能类似于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
模块。接着将命令行的前两个参数分别赋值给
$source

$dest
。如果
$dest
是一个目录,就从
$source
中提取基本文件名,并将其追加到
$dest
目录路径后。最后执行重命名操作,如果失败则输出错误信息。

29、编写一个程序,将以下哈希表的数据按姓氏进行不区分大小写的字母顺序排序。当姓氏相同时,再按名字(同样不区分大小写)排序。输出的第一个名字应该是 Fred 的,最后一个应该是 Betty 的。所有同姓的人应该分组在一起。不要修改数据。名字的大小写应与下面所示保持一致。哈希表数据为: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 $person (@sorted_names) {
    print "$person $last_name{$person}
";
}

此代码首先定义了一个哈希表
%last_name
,然后使用
sort
函数对哈希表的键进行排序。排序规则为:先按姓氏的小写形式进行字母顺序排序,若姓氏相同,则按名字的小写形式排序。最后,遍历排序后的名字列表并输出名字和对应的姓氏。

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

程序会报告位置 0、10 和 13。因为在字符串
"This is a test."
中,第一个
't'
在位置 0,第二个
't'
在位置 10,第三个
't'
在位置 13。

31、编写一个使用
given - when
结构的程序,该程序接收一个数字作为输入,若该数字能被 3 整除则打印“Fizz”,能被 5 整除则打印“Bin”,能被 7 整除则打印“Sausage”。对于像 15 这样的数字,由于它能同时被 3 和 5 整除,所以应打印“Fizz”和“Bin”。那么,程序打印“Fizz Bin Sausage”的第一个数字是多少?

能同时被 3、5、7 整除的最小数字是它们的最小公倍数,即 $3 imes 5 imes 7 = 105$,所以第一个打印“Fizz Bin Sausage”的数字是 105

32、使用
given
和智能匹配,编写一个程序,报告你在命令行中指定数字的所有约数(除了 1 和该数字本身)。例如,对于数字 99,程序应报告它能被 3、9、11 和 33 整除。如果该数字是质数(没有约数),则报告该数字是质数。如果命令行参数不是数字,则报告错误,并且不尝试计算约数。尽管可以使用
if
结构和普通匹配来实现,但请仅使用智能匹配。

以下是满足需求的程序代码:


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

33、编写一个程序,输入一个数字,使其能报告该数字是奇数还是偶数,该数字是否为质数(除了 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 是 @divisors 中的元素
        say "$_ is even";
        continue;
    }
    when( !( @divisors ~~ 2 ) ) { # 2 不是 @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;
}

34、编写一个程序,切换到某个特定的(硬编码)目录,如系统的根目录,然后执行
ls -l
命令以获取该目录的长格式目录列表。(如果你使用的是非 Unix 系统,请使用你自己系统的命令来获取详细的目录列表)。

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


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

第一行将当前工作目录更改为根目录,第二行使用多参数的
exec
函数将结果发送到标准输出。

35、修改之前的程序,将命令的输出发送到当前目录下名为 ls.out 的文件中。错误输出应发送到名为 ls.err 的文件中。(无需特别处理这两个文件可能为空的情况)

在 Perl 中,可以使用以下方式实现将命令输出发送到
ls.out
文件,错误输出发送到
ls.err
文件:


system 'ls > ls.out 2> ls.err';

这里使用了 shell 的重定向功能,
>
用于将标准输出重定向到
ls.out
文件,
2>
用于将标准错误输出重定向到
ls.err
文件。

36、(仅适用于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>
替换为上述程序实际运行时的进程ID。

37、使用 Perl 语言输出“Hello, world!”,可以有哪些实现方式?

有以下几种实现方式:

使用
print
语句:

perl print "Hello, world!
";

若使用 Perl 5.10 或更高版本,可使用
say
语句:

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

在命令行不创建文件直接运行,使用
-e
开关:

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

使用
-l
开关自动添加换行符:

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

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

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


#!/usr/bin/perl
use 5.010;

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

将上述代码保存为一个
.pl
文件,例如
circle_circumference.pl
,然后在终端中运行
perl circle_circumference.pl
即可看到结果。这里圆周率取 3.14159,你也可以根据需要使用更精确的值。

39、编写一个 Perl 程序,从用户输入获取圆的半径,然后计算并输出该圆的周长

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


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

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

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

这个程序首先提示用户输入圆的半径,获取输入后去除换行符,接着使用圆周长公式
2 * π * 半径
计算周长,最后输出结果。

40、编写一个Perl程序,计算并打印半径硬编码为12.5的圆的周长。


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

41、编写一个Perl程序,向用户询问圆的半径,然后计算并打印出圆的周长。


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

42、编写一个Perl程序,向用户询问圆的半径,检查半径是否为负数,然后计算并打印圆的周长。如果半径为负数,周长应为0。


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

43、编写一个Perl程序,要求用户输入一个字符串和一个重复次数,然后将该字符串重复指定次数并打印输出,每个字符串占一行。


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

44、编写程序,让用户输入一些行,然后按 Ctrl – D(或 Ctrl – Z)结束输入,将输入的行反转后输出

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


lines = []
while True:
    try:
        line = input()
        lines.append(line)
    except EOFError:
        break
reversed_lines = lines[::-1]
for line in reversed_lines:
    print(line)

在这个程序中,首先创建一个空列表
lines
用于存储用户输入的每一行。使用
while True
创建一个无限循环,在循环内部使用
input()
函数获取用户输入的每一行,并将其添加到
lines
列表中。当用户按下
Ctrl-D
(在 Windows 系统上是
Ctrl-Z
)时,会触发
EOFError
异常,此时使用
break
语句跳出循环。接着,使用切片操作
[::-1]

lines
列表中的元素反转,最后遍历反转后的列表并逐行输出。

45、编写程序,让用户输入一些行,按 Ctrl – D 结束输入,将输入的行排序后输出,分别实现输出在一行和输出在多行的情况

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


lines = []
while True:
    try:
        line = input()
        lines.append(line)
    except EOFError:
        break

# 输出在多行
print('输出在多行:')
for line in sorted(lines):
    print(line)

# 输出在一行
print('输出在一行:')
print(' '.join(sorted(lines)))

上述代码首先让用户输入多行内容,按 Ctrl-D 结束输入,将输入的行存储在列表中。然后对列表进行排序,分别实现了多行输出和一行输出排序后的内容。

46、编写一个子程序,计算传入参数的总和

以下是一个简单的 Perl 子程序示例,用于计算传入参数的总和:


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

你可以使用以下方式调用这个子程序:


my $result = sum(1, 2, 3, 4);
print $result; # 输出 10

47、编写程序,让用户输入一个字符串和一个数字,将字符串重复该数字次数后输出,要求字符串在单独的行上

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


string = input("请输入一个字符串:")
number = int(input("请输入一个数字:"))
for _ in range(number):
    print(string)

这段代码首先让用户输入一个字符串和一个数字,然后使用
for
循环将字符串重复指定的次数,每次循环都将字符串打印在单独的一行上。

48、编写一个子程序
total
,用于计算传入参数的总和

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


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

上述代码定义了一个名为
total
的子程序,它使用
foreach
循环遍历传入的参数列表
@_
,将每个参数累加到变量
$sum
中,最后返回总和。

49、调用一个名为
total
的子程序,计算1到1000的数字总和

可使用以下代码实现:
my $sum = total(1..1000);
,这里
total
是一个子程序,
1..1000
表示从 1 到 1000 的数字序列,将该序列作为参数传递给
total
子程序即可计算总和。

50、编写一个子程序
average
,用于计算传入参数的平均值;再编写一个子程序
above_average
,用于返回传入参数中大于平均值的元素组成的列表

以下是实现
average

above_average
子程序的代码:


sub average {
    if (@_ == 0) {
        return undef;
    }
    my $sum = 0;
    foreach my $num (@_) {
        $sum += $num;
    }
    return $sum / @_;
}

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


average
子程序中,如果传入的参数列表为空,返回
undef
;否则计算参数的总和并除以参数的数量得到平均值。在
above_average
子程序中,先调用
average
子程序计算平均值,然后遍历参数列表,将大于平均值的元素添加到一个新列表中并返回。

51、编写一个
greet
子程序,使用状态变量记住最后一个打招呼的人

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


use 5.010;
greet( 'Fred' );
greet( 'Barney' );
greet( 'Wilma' );
greet( 'Betty' );
sub greet {
    state $last_name;
    my $name = shift;
    print "Hi $name! ";
    if( defined $last_name ) {
        print "The last person I greeted was: $last_name
";
    } else {
        print "You are the first one here!
";
    }
    $last_name = $name;
}

在上述代码中,
greet
子程序使用了状态变量
$last_name
来记住最后一个打招呼的人。每次调用
greet
子程序时,会根据
$last_name
是否有值来输出不同的信息,并且更新
$last_name
为当前打招呼的人。

52、编写一个
greet
子程序,使用状态变量记住所有打招呼的人

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


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

这段代码定义了一个
greet
子程序,使用
state
关键字声明了一个状态变量
@names
,用于记住所有打招呼的人。每次调用
greet
子程序时,会根据
@names
数组是否为空输出不同的欢迎信息,并将当前打招呼的人的名字添加到
@names
数组中。

© 版权声明

相关文章

暂无评论

none
暂无评论...