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

55、编写代码将命令行参数(UTF – 8编码)转换为对应的字符并打印

以下两种方式都可实现将命令行参数(UTF-8 编码)转换为对应的字符并打印:

方式一:


use utf8;
use Encode qw(encode decode);
my $string = decode('UTF-8', shift);
my $length = length($string);
$string = encode('UTF-8', $string);
print "$string has $length characters
";

方式二(使用

utf8::all

模块):


use utf8::all;
my $string = shift @ARGV;
my $length = length($string);
print "$string has $length characters
";

56、编写代码将命令行参数(UTF – 8编码)的每个字符转换为对应的Unicode码点并打印

可以使用以下Perl代码实现该功能:


#!/usr/bin/perl
use strict;
use warnings;
use Encode 'decode_utf8';

foreach my $arg (@ARGV) {
    my $decoded = decode_utf8($arg);
    foreach my $char (split //, $decoded) {
        my $codepoint = ord($char);
        print sprintf("U+%04X
", $codepoint);
    }
}

将上述代码保存为一个

.pl

文件,比如

codepoint.pl

,然后在命令行运行

perl codepoint.pl 你的参数

即可将参数中每个字符转换为对应的Unicode码点并打印。

57、编写代码将命令行参数(UTF – 8编码)的每个字符转换为对应的Unicode码点并打印,要求码点格式为U+xxxx

以下是一个Perl代码示例,可将命令行参数(UTF-8编码)的每个字符转换为对应的Unicode码点并以

U+xxxx

格式打印:


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

foreach my $arg (@ARGV) {
    foreach my $char (split //, $arg) {
        my $codepoint = sprintf("U+%04X", ord($char));
        print $codepoint, "
";
    }
}

将上述代码保存为一个

.pl

文件,例如

unicode_converter.pl

,然后在命令行中运行:


perl unicode_converter.pl 你输入的参数

代码会将每个参数的字符转换为对应的Unicode码点并打印。

58、当添加 Convert::Distance::Metric 后,lib/ 目录的文件布局应该是怎样的?


lib/
└── Convert/
    └── Distance/
        ├── Imperial.pm
        └── Metric.pm

59、添加 Convert::Distance::Metric 后,查看 lib/ 目录文件布局以及更新 MANIFEST 文件内容,并说明具体情况

添加

Convert::Distance::Metric

后,

lib/

目录文件布局如下:


lib/
└── Convert/
    └── Distance/
        ├── Imperial.pm
        └── Metric.pm

更新后的

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

60、编写一个程序,使用 Convert::Distance::Metric 模块进行公里和米的转换并输出结果

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


use Convert::Distance::Metric ":all";
# 把3.5公里转换为米
my $meters = kilometers_to_meters(3.5);
print "3.5公里等于 $meters 米
";
# 把转换后的米数再转换回公里
my $kilometers = meters_to_kilometers($meters);
print "$meters 米等于 $kilometers 公里
";

此程序借助

Convert::Distance::Metric

模块把3.5公里转换为米,接着再将结果转换回公里,最后输出转换结果。

61、编写一个名为 Person 的类,包含初始化、获取姓名、出生日期和年龄等方法

以下是实现该需求的代码:


package Person;
use strict;
use warnings;
use DateTime;
use Carp 'croak';

sub new {
    my ( $class, $args ) = @_;
    my $self = bless {} => $class;
    $self->_initialize($args);
    return $self;
}

sub _initialize {
    my ( $self, $args ) = @_;
    my %args = %$args;
    my $name = delete $args{name};
    my $birthdate = delete $args{birthdate};
    unless ( $name && $name =~ /S/ ) {
        croak "Person name must be supplied";
    }
    unless ( eval { $birthdate->isa('DateTime') } ) {
        croak "Person birthdate must be a DateTime object";
    }
    $self->{name} = $name;
    $self->{birthdate} = $birthdate;
}

sub name {
    $_[0]->{name}
}

sub birthdate {
    $_[0]->{birthdate}
}

sub age {
    my $self = shift;
    my $duration = DateTime->now - $self->birthdate;
    return $duration->years;
}

1;

该代码定义了一个

Person

类,其中

new

方法用于创建对象,

_initialize

方法用于初始化对象属性,

name

方法用于获取姓名,

birthdate

方法用于获取出生日期,

age

方法用于计算并返回年龄。

62、请写出 Person 类的一种实现方式

以下是

Person

类的一种实现方式:


package Person;
use Moose;

has 'given_name' => (is => 'ro', required => 1);
has 'family_name' => (is => 'ro', required => 1);
has 'birthdate' => (is => 'ro', required => 1);
has 'title' => (is => 'rw');

sub name {
    my $self = shift;
    my $title = $self->title ? $self->title . ' ' : '';
    return $title . $self->given_name . ' ' . $self->family_name;
}

sub age {
    my $self = shift;
    # 这里简单假设返回一个大于 100 的值,实际中应根据 birthdate 计算
    return 101;
}

1;

此实现运用了 Moose 模块来定义类和属性,包含

given_name


family_name


birthdate


title

属性,还有

name


age

方法。

name

方法返回完整姓名,可包含头衔;

age

方法返回一个大于 100 的值,实际使用时应依据

birthdate

计算。

63、指出代码中存在的问题

文中提到两个代码相关问题:

正则表达式难以手动编写和调试;

Web应用未对用户提供的数据进行编码,导致页面可能出现安全问题。

64、请写出 Customer 类的实现方式


要实现 `Customer` 类,需先定义模式。假设顶级命名空间是 `Loki::`,可在 `lib/Loki/Schema.pm` 中定义模式,示例如下:

1. 定义 `Customer` 结果类:

    ```perl
    package Loki::Schema::Result::Customer;
    use base 'DBIx::Class::Core';

    __PACKAGE__->table('customers');

    __PACKAGE__->add_columns(
        'id',
        {
            data_type         => 'integer',
            is_auto_increment => 1,
            is_nullable       => 0,
        },
        'first_name',
        {
            data_type   => 'varchar',
            size        => 256,
            is_nullable => 0,
        },
        'last_name',
        {
            data_type   => 'varchar',
            size        => 256,
            is_nullable => 0,
        },
    );

    __PACKAGE__->set_primary_key('id');

    __PACKAGE__->has_many('orders', 'Loki::Schema::Result::Order', 'customer_id');
    ```

2. 定义 `Order` 结果类:

    ```perl
    package Loki::Schema::Result::Order;
    use base 'DBIx::Class::Core';

    __PACKAGE__->table('orders');

    __PACKAGE__->add_columns(
        'id',
        {
            data_type         => 'integer',
            is_auto_increment => 1,
            is_nullable       => 0,
        },
        'customer_id',
        {
            data_type     => 'integer',
            is_foreign_key => 1,
            is_nullable   => 0,
        },
        'total',
        {
            data_type => 'decimal',
            size      => [10, 2],
            is_nullable => 0,
        },
    );

    __PACKAGE__->set_primary_key('id');

    __PACKAGE__->belongs_to('customer', 'Loki::Schema::Result::Customer', 'customer_id');
    ```

3. 使用模式:

    ```perl
    use Loki::Schema;

    my $schema = Loki::Schema->connect($dsn, $user, $pass, %optional_attributes);

    my $customer_rs = Loki::Schema::Result::Customer->resultset('Customer');

    while ( my $customer = $customer_rs->next ) {
        my $orders_rs = $customer->orders;
        my $total = 0;

        while ( my $order = $orders_rs->next ) {
            $total += $order->total;
        }

        printf "Customer: %40s Total: %0.2f", $customer->full_name, $total;
    }
    ```
</markdown>

##65、实现一个User类,包含username和password属性,对password进行MD5加密,并提供password_eq方法判断密码是否相等,同时可以测试该类。
以下是实现该功能的代码:

```perl
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');

上述代码定义了一个

User

类,包含

username


password

属性。在

BUILD

方法中,将

password

转换为 MD5 摘要。

password_eq

方法用于验证新密码是否与旧密码匹配。最后给出了测试该类的代码。

66、实现一个unique函数,返回列表中唯一元素,并按原列表顺序排列,同时进行测试

以下是使用Python实现的

unique

函数及其测试代码:


def unique(lst):
    seen = set()
    result = []
    for item in lst:
        if item not in seen:
            result.append(item)
            seen.add(item)
    return result

# 测试代码
input_list = [3, 4, 1, 4, 7, 7, 4, 1, 3, 8]
output_list = unique(input_list)
print(output_list)

上述代码定义了

unique

函数,它接受一个列表作为输入,使用集合

seen

来记录已经出现过的元素,遍历列表时,若元素未出现过,则添加到结果列表中并更新集合。最后返回按原列表顺序排列的唯一元素列表,并进行了简单的测试。

67、修改 unique 函数,使其返回的唯一元素按顺序排列,并进行测试

以下是修改后的代码及测试:


use Test::Most;
sub unique {
    my @array = @_;
    my %seen;
    my @unique;
    foreach my $element (@array) {
        push @unique, $element unless $seen{$element}++;
    }
    return @unique;
}
my @have = unique( 2, 3, 5, 4, 3, 5, 7 );
my @want = ( 2, 3, 5, 4, 7 );
is_deeply @have, @want, 'unique() should return unique() elements in order';
done_testing;

此代码中,

unique

函数会遍历输入数组并将未出现过的元素按顺序存入

@unique

数组,最后返回该数组。测试部分使用

is_deeply

函数比较

@have


@want

数组是否相等,以验证

unique

函数是否按顺序返回唯一元素。

68、请详细说明

Scalar::Util

模块中的

looks_like_number

函数,并给出使用示例


`Scalar::Util`模块在Perl 5.7.3版本被纳入Perl核心,其中的`looks_like_number`函数可返回一个布尔值,用于判断一个字符串是否看起来像数字。

使用该函数前,需显式导入,示例如下:
```perl
use Scalar::Util 'looks_like_number';

使用示例:


my $is_number = looks_like_number('3fred');

此例中返回

false


my $is_number = looks_like_number('3e7');

此例中返回

true

在处理数据时,可利用该函数进行数据验证,如在

average

函数中,会遍历传入的参数,使用

looks_like_number

检查每个参数是否为数字,若不是则抛出错误。


sub average {
    my @numbers = @_;
    my $sum = 0;
    foreach my $num (@numbers) {
        die "$num is not a number" unless looks_like_number($num);
        $sum += $num;
    }
    return $sum / @_;
}

69、在查看测试的 @want 数组时,研究 unique 函数,使其返回原始列表中按找到顺序排列的唯一元素。

可以将

unique

函数改写如下:


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

此函数借助一个哈希表

%seen

来记录已出现的元素,遍历数组时,若元素未出现过,就将其添加到

@unique

数组里,从而保证返回的唯一元素按原始列表中的顺序排列。

70、原 unique 函数返回的元素顺序是哈希键的顺序,是随机的,如何让 unique 函数返回按顺序排列的唯一元素。

对返回的元素进行排序即可,使用相同的排序行为处理实际结果和预期结果数组,不必进行数值排序。

示例代码为:


is_deeply [ sort @have ], [ sort @want ], 'unique() 应按顺序返回唯一元素';

71、对于 reciprocal 函数的参数,如何判断其是否为合法数字以避免错误情况。


可使用 `Scalar::Util` 模块中的 `looks_like_number` 函数判断参数是否为数字。若不是数字,使用 `croak` 函数抛出错误信息,代码示例如下:

```perl
sub reciprocal {
    my $number = shift;
    unless ( looks_like_number($number) ) {
        croak("Argument to reciprocal() must be a number");
    }
    unless ($number) {
        croak("Illegal division by zero");
    }
    return 1 / $number;
}


##72、原 TestsFor::TV::Episode 中 %default_attributes 硬编码在测试方法中,如何重写 TestsFor::TV::Episode 以及编写 TestsFor::TV::Episode::Broadcast 的测试。
```markdown
重写 `TestsFor::TV::Episode` 时,将 `%default_attributes` 提取到单独的方法中。示例如下:

```perl
package TestsFor::TV::Episode;
use Test::Most;

sub default_attributes {
    my $test = shift;
    return (
        series       => 'Firefly',
        director     => 'Marita Grabiak',
        title        => 'Jaynestown',
        genre        => 'awesome',
        season       => 1,
        episode_number => 7,
    );
}

sub attributes {
    my $test = shift;
    my %default_attributes = $test->default_attributes;
    my $class = $test->class_to_test;
    my $episode = $class->new(%default_attributes);

    while (my ($attribute, $value) = each %default_attributes) {
        can_ok $episode, $attribute;
        is $episode->$attribute, $value, "The value for '$attribute' should be correct";
    }

    my %attributes = %default_attributes;
    foreach my $attribute (qw/season episode_number/) {
        $attributes{$attribute} = 0;
        throws_ok { $class->new(%attributes) } qr/Q($attribute) does not pass the type constraint/,
            "Setting $attribute to less than zero should fail";
    }
}

1;

编写

TestsFor::TV::Episode::Broadcast

的测试时,继承

TestsFor::TV::Episode

并扩展

default_attributes

方法添加

broadcast_date

属性,同时使用

Tests(+2)

声明额外的测试。示例如下:


package TestsFor::TV::Episode::Broadcast;
use Test::Most;
use DateTime;
use base 'TestsFor::TV::Episode';

sub default_attributes {
    my $test = shift;
    my %attributes = $test->SUPER::default_attributes;
    $attributes{broadcast_date} = DateTime->new(
        year  => 2002,
        month => 10,
        day   => 8,
    );
    return %attributes;
}

sub attributes : Tests(+2) {
    my $test = shift;
    $test->SUPER::attributes;
}

1;

© 版权声明

相关文章

暂无评论

none
暂无评论...