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、创建一个哈希,键为水果名称,值为它们的常见颜色,然后将每个键/值对作为单独的一行打印出来,格式类似于“香蕉是黄色的”。

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


use strict;
use warnings;
use diagnostics;
my %color_for = ( 
    bananas => 'yellow', 
    apples =>'red', 
    oranges => 'orange',
);
for my $fruit (keys %color_for) {
    my $color = $color_for{$fruit};
    print "$fruit are $color
";
}

2、从 @fahrenheit 数组创建 @celsius 数组。

要从

@fahrenheit

数组创建

@celsius

数组,需要将

@fahrenheit

数组中的每个华氏温度值转换为摄氏温度值。转换公式是先减去 32,然后乘以 5/9。可以使用以下代码实现:


my @fahrenheit = ( 0, 32, 65, 80, 212 );
my @celsius = map { ( $_ - 32 ) * 5 / 9 } @fahrenheit;

3、将数字 1 到 10 逐行打印。

在 Perl 中可以使用以下代码实现:


for (my $i = 1; $i <= 10; $i++) {
    print $i, "
";
}

4、计算并打印@numbers数组中数字的平均值。

可以使用以下代码实现:


sub average {
    my @numbers = @_;
    my $total = 0;
    $total += $_ foreach @numbers;
    return $total / @numbers;
}

print average(qw< 1 5 18 3 5>);

此代码先定义一个

average

子例程,在子例程中计算总和并除以元素数量得到平均值,最后调用该子例程并打印结果。

5、修复 C 风格 for 循环中的越界错误,并展示使用 Perl 风格 for/foreach 循环的更好方法。

修复 C 风格

for

循环中的越界错误,需将循环终止条件从


$i <= $num_elements

改为


$i < $num_elements

更好的方法是使用 Perl 风格的

for

/

foreach

循环,示例代码如下:


my @array = qw( fee fie foe fum );
for my $word (@array) {
    print "$word";
}

这种循环能避免越界错误。

6、编写代码为 %stat_for 哈希中的键分配随机值,键为’strength’、’intelligence’、’dexterity’,随机值为 2 加上两个 1 到 6 的随机整数之和,且随机值不能小于 6,最后输出每个键及其对应的值。


my %stat_for;
my @stats = ('strength', 'intelligence', 'dexterity');

foreach my $stat (@stats) {
    my $random = 2 + int(rand(6)) + int(rand(6));
    redo if $random < 6;
    $stat_for{$stat} = $random;
}

print <<"END_CHARACTER";
Strength: $stat_for{strength}
Intelligence: $stat_for{intelligence}
Dexterity: $stat_for{dexterity}
END_CHARACTER

7、创建一个完整的代码,为 %stat_for 哈希中的键分配随机值,条件是该值至少为 6,并打印结果。


my %stat_for;
my @stats = ('strength', 'intelligence', 'dexterity');
foreach my $stat (@stats) {
    my $random;
    do {
        $random = 2 + int(rand(6)) + int(rand(6));
    } while ($random < 6);
    $stat_for{$stat} = $random;
}
print <<"END_CHARACTER";
Strength: $stat_for{strength}
Intelligence: $stat_for{intelligence}
Dexterity: $stat_for{dexterity}
END_CHARACTER

8、创建一个包含值 1 到 5 的数组 @first,创建它的引用,然后从该引用创建另一个数组 @second。打印这两个数组。

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


my @first = (1..5);
my $first_ref = @first;
my @second = @$first_ref;
print "@first
";
print "@second
";

上述代码首先创建了包含 1 到 5 的数组

@first

,接着创建了它的引用

$first_ref

,然后从引用创建了数组

@second

,最后打印了这两个数组。

9、根据给定的 $sales 哈希表,计算吉姆在周五的销售数量和总销售额,并打印结果。$sales 哈希表结构如下:{ friday => { jim => [ 1, 1, 5 ], mary => [ 2 ] } }

代码示例如下:


my $sales = { friday => { jim => [ 1, 1, 5 ], mary => [ 2 ] }, };
my $friday = $sales->{friday}{jim};
my $num_sales = @$friday;
my $total = 0;
$total += $_ foreach @$friday;
print "Jim had $num_sales sales, for a total of $total dollars
";

10、以两种不同的方式从 $score_for 哈希中提取 Jim 和 Mary 的分数并打印出来。


第一种方式:
my ( $jim, $mary ) = @$score_for{ qw{Jim Mary} };
print "$jim $mary";

第二种方式:
$jim = $score_for->{Jim};
$mary = $score_for->{Mary};
print "$jim $mary";

11、编写一个名为 average 的子程序,用于计算传入数字的平均值,并打印给定一组数字的计算结果。

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


sub average {
    my $numbers = @_;
    my $total = 0;
    $total += $_ foreach @$numbers;
    my $average = $total / scalar @$numbers;
    return $average;
}
my @numbers = (1, 2, 3, 4, 5);
my $result = average(@numbers);
print $result;

上述代码定义了

average

子程序,它接收一组数字,计算其总和,然后除以数字的数量得到平均值并返回。最后,给定一组数字调用该子程序并打印结果。

12、编写一个名为make_multiplier的子程序,该子程序返回一个子程序,该返回的子程序将其输入乘以给定的数字。用不同的数字进行测试。

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


sub make_multiplier {
    my $num = shift;
    return sub {
        my $input = shift;
        return $input * $num;
    };
}

my $times_seven = make_multiplier(7);
my $times_five = make_multiplier(5);

print 21 == $times_seven->(3) ? "yes
" : "no
";
print 20 == $times_five->(4) ? "yes
" : "no
";

代码中定义了

make_multiplier

子程序,它接受一个数字作为参数,并返回一个匿名子程序。这个匿名子程序接受一个输入数字,并将其乘以

make_multiplier

传入的数字。最后使用不同的数字进行了测试。

13、编写一个递归子例程 sum 来计算传入数字的总和,并打印给定一组数字的计算结果。

以下是一个递归子例程

sum

的示例代码:


sub sum {
    my @numbers = @_;
    if (@numbers == 0) {
        return 0;
    } else {
        my $first = shift @numbers;
        return $first + sum(@numbers);
    }
}

my @given_numbers = (1, 2, 3, 4, 5);
print sum(@given_numbers);

这段代码定义了递归子例程

sum

,当传入数字为空时返回 0,否则取出第一个数字并递归调用

sum

计算剩余数字的和,最后将第一个数字与剩余数字的和相加。最后使用给定的一组数字调用该子例程并打印结果。

14、使用正则表达式从给定文本中提取员工姓名及其对应的编号,并以哈希形式打印结果。给定文本为:alice: 48472

bob:34582

we need to fire charlie

charlie : 45824

denise is a new hire

denise : 34553

可以使用以下代码实现:


use strict;
use warnings;
use Data::Dumper;

my $employee_numbers = <<'END_EMPLOYEES';
alice: 48472
bob:34582
# we need to fire charlie
charlie : 45824
# denise is a new hire
denise : 34553
END_EMPLOYEES

my %employee_number_for;
while ( $employee_numbers =~ /^ s* (w+) s* : s* (d{5}) s* $/gmx ) {
    $employee_number_for{$1} = $2;
}

print Dumper \%employee_number_for;

执行上述代码后,输出结果如下:


$VAR1 = { 'alice' => '48472', 'denise' => '34553', 'charlie' => '45824', 'bob' => '34582' };

15、将命令行参数中的单词列表进行 UTF – 8 解码,将其拆分为字符,获取每个字符的 Unicode 码点并打印出来。

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


use strict;
use warnings;
use Encode 'decode';
binmode STDOUT, ':encoding(UTF-8)';
foreach my $word (@ARGV) {
    $word = decode('UTF-8', $word);
    my @chars = split //, $word;
    foreach my $char (@chars) {
        $char = "U+" . uc sprintf "%04x", ord $char;
        print "$char ";
    }
    print "
";
}

上述代码首先对命令行参数中的每个单词进行 UTF – 8 解码,然后将其拆分为字符,接着获取每个字符的 Unicode 码点并将其转换为

U+XXXX

的格式,最后进行打印。

16、对给定的十六进制数字按降序排序,并以十六进制格式输出结果。

可使用以下代码实现:


my @numbers = ( 0x23, 0xAA, 0xaa, 0x01, 0xfB );
my @sorted = sort { $b <=> $a } @numbers;
print join ', ' => map { sprintf '0x%X', $_ } @sorted;

输出结果为:


0xFB, 0xAA, 0xAA, 0x23, 0x01

17、使用grep的块形式和表达式形式,找出@numbers数组中的所有完全平方数,并按升序排序。同时,处理数组中包含非数字字符串的情况。

块形式:


my @numbers = ( 28, 49, 1000, 4, 25, 49, 529 );
my @squares = sort { $a <=> $b } grep { /^[0-9]+$/ && ( int(sqrt($_)) == sqrt($_) ) } @numbers;
print join ', ' => @squares;

表达式形式:


my @squares = sort { $a <=> $b } grep /^[0-9]+$/ && ( int(sqrt($_)) == sqrt($_) ), @numbers;

也可以写成:


my @squares = sort { $a <=> $b } grep(/^[0-9]+$/ && ( int(sqrt($_)) == sqrt($_)), @numbers);

这里使用正则表达式

/^[0-9]+$/

确保只处理正整数,从而处理数组中包含非数字字符串的情况。

18、从 @list 数组中移除重复元素,并返回一个包含唯一元素的新数组。

可以使用以下代码实现:


sub unique {
    my @array = @_;
    my %seen;
    my @unique;
    foreach my $element (@array) {
        push @unique, $element unless $seen{$element}++;
    }
    return @unique;
}

my @list = qw( bob sally Andromalius sally bob ned Andromalius );
my @unique_list = unique(@list);
print join(', ', @unique_list); # 可添加此句打印结果以验证

19、过滤 @employees 数组,仅包含服务年限超过 1 年的员工,按姓氏排序,使用 map、sort 和 grep 创建一个包含他们全名的新数组。另外,使用 for 循环重写代码。

使用 map、sort 和 grep 的代码


my @employees = (
  { first_name => 'Sally', last_name => 'Jones', years => 4, payscale => 4, },
  { first_name => 'Abby', last_name => 'Hoffman', years => 1, payscale => 10, },
  { first_name => 'Jack', last_name => 'Johnson', years => 4, payscale => 5, },
  { first_name => 'Mr.', last_name => 'Magnate', years => 12, payscale => 1, },
);
my @names = sort { $a cmp $b} map { $_->{first_name} . ' ' . $_->{last_name}} grep { $_->{years} > 1} @employees;
foreach my $name (@names) {
  print $name . "
";
}

使用 for 循环重写的代码


my @employees = (
  { first_name => 'Sally', last_name => 'Jones', years => 4, payscale => 4, },
  { first_name => 'Abby', last_name => 'Hoffman', years => 1, payscale => 10, },
  { first_name => 'Jack', last_name => 'Johnson', years => 4, payscale => 5, },
  { first_name => 'Mr.', last_name => 'Magnate', years => 12, payscale => 1, },
);
my @filtered_employees;
foreach my $employee (@employees) {
  if ($employee->{years} > 1) {
    push @filtered_employees, $employee;
  }
}
my @sorted_employees = sort { $a->{last_name} cmp $b->{last_name}} @filtered_employees;
my @names;
foreach my $employee (@sorted_employees) {
  push @names, $employee->{first_name} . ' ' . $employee->{last_name};
}
foreach my $name (@names) {
  print $name . "
";
}

20、将 Convert::Distance::Metric 模块添加到 lib/ 目录并更新 MANIFEST 文件。

将模块文件

lib/Convert/Distance/Metric.pm

放置到

lib/

目录下,更新

MANIFEST

文件,使其包含以下内容:

Changes

lib/Convert/Distance/Imperial.pm

lib/Convert/Distance/Metric.pm

Makefile.PL

MANIFEST

README

t/00 – load.t

t/manifest.t

t/pod – coverage.t

t/pod.t

21、为 Convert::Distance::Metric 模块添加 POD 文档。

为简便起见,我们将在最后的

__END__

字面量之后添加 POD。如下:


__END__

=head1 NAME

Convert::Distance::Metric - Convert kilometers to meters and back

=head1 SYNOPSIS

use Convert::Distance::Metric ":all";

print kilometers_to_meters(7);
print meters_to_kilometers(3800);

=head1 DESCRIPTION

This is a simple module to convert kilometers to meters and back. It’s mainly here to show how modules are built and documented.

=head1 EXPORT

The following functions may be exported on demand. You can export all of them with: `use Convert::Distance::Metric ':all';`

=over 4

22、创建一个继承自 Person 类的 Customer 类,要求客户必须至少 18 岁。

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


package Customer;
use Moose;
extends 'Person';
use Carp 'croak';
use namespace::autoclean;

sub BUILD {
    my $self = shift;
    if ( $self->age < 18 ) {
        my $age = $self->age;
        croak("Customers must be 18 years old or older, not $age");
    }
}

__PACKAGE__->meta->make_immutable;
1;

23、使用Moose创建一个User类,包含用户名和密码属性,对密码进行哈希处理,并提供一个方法来检查给定的密码是否正确。测试该类。

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


package User;
use Moose;
use Digest::MD5 'md5_hex';
use namespace::autoclean;

has username => ( is => 'ro', isa => 'Str', required => 1 );
has password => ( is => 'ro', isa => 'Str', writer => '_set_password',);

sub BUILD {
    my $self = shift;
    $self->_set_password(md5_hex($self->password));
}

sub password_eq {
    my ( $self, $password ) = @_;
    $password = md5_hex($password);
    return $password eq $self->password;
}

__PACKAGE__->meta->make_immutable;
1;

# 测试代码
my $user = User->new( username => 'Ovid', password => 'Corinna',);
print $user->dump;
print "Yes" if $user->password_eq('Corinna');
© 版权声明

相关文章

暂无评论

none
暂无评论...