Perl编程实践:从基础到文件操作

内容分享15小时前发布
0 0 0

1、编写并运行一个输出“Hello, world”的Perl程序,以此来测试Perl环境是否正常工作。

以下几种方式可实现“Hello, world”程序:

创建文件,内容为

perl
print "Hello, world!
";


运行

perl 文件名



若 Perl 版本为 v5.10 或更高,文件内容可写为

perl
use v5.10;
say "Hello, world!";


再运行。

不创建文件,在命令行使用

-e

开关:

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


使用

-l

开关自动添加换行符:

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


在 Windows 的

command.exe

(或

cmd.exe

)中,引号使用要调整,如

cmd
C:> perl -le "print 'Hello, World'"


也可使用广义引号

cmd
C:> perl -le "print q(Hello, World)"


Perl v5.10 及更高版本使用

-E

开关启用新特性并使用

say



bash
$ perl -E 'say "Hello, World"'

2、编写一个程序,计算半径为 12.5 的圆的周长。圆的周长是 2π乘以半径(约为 2 乘以 3.141592654)。你得到的答案应该约为 78.5。


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

3、编写一个 Perl 程序,提示用户输入一个圆的半径,然后计算并输出该圆的周长。例如,当用户输入的半径为 12.5 时,程序应计算并输出该半径对应的圆的周长。


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

4、编写一个程序,提示用户输入两个数字(分别在不同的输入行),并输出这两个数字相乘的结果。


print 'Enter first number: ';
chomp($one = <STDIN>);
print 'Enter second number: ';
chomp($two = <STDIN>);
$result = $one * $two;
print "The result is $result.
";

5、编写一个程序,提示用户输入一个字符串和一个数字(分别在不同的输入行),然后将该字符串按照数字指定的次数分行输出。(提示:使用 x 运算符)。如果用户输入“fred”和“3”,输出应该是三行,每行都显示“fred”。如果用户输入“fred”和“299792”,可能会有大量输出。

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


print "请输入一个字符串:";
my $string = <STDIN>;
chomp($string);
print "请输入一个数字:";
my $number = <STDIN>;
chomp($number);
print ($string . "
") x $number;

这段代码首先提示用户输入一个字符串和一个数字,然后使用

x

运算符将字符串重复指定的次数,并在每次重复后添加换行符,最后将结果输出。

6、编写一个程序,逐行读取字符串列表,直到输入结束,然后按逆序输出该列表。如果输入来自键盘,在Unix系统上可能需要按Control – D,在Windows系统上可能需要按Control – Z来表示输入结束。

在 Perl 语言中,原答案

print reverse <>;

可以实现该功能,但表述不够完整。以下是一个更完整的 Python 实现示例:


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

7、编写一个程序,逐行读取一系列数字,直到输入结束。然后,针对每个输入的数字,从以下列表中打印出对应的人名。将这个人名列表硬编码到程序中,即它应出现在程序的源代码中。人名列表为:fred betty barney dino wilma pebbles bamm – bamm。例如,如果输入的数字是1、2、4和2,输出的人名将是fred、betty、dino和betty。

以下是一个Python示例代码来解决这个问题:


names = ['fred', 'betty', 'barney', 'dino', 'wilma', 'pebbles', 'bamm - bamm']
while True:
    try:
        num = int(input())
        if 1 <= num <= len(names):
            print(names[num - 1])
    except EOFError:
        break

以上代码定义了一个人名列表

names

,然后通过

while True

循环不断读取输入的数字,将输入的数字转换为整数后,检查其是否在有效范围内(1到列表长度),如果是则打印对应的人名。当遇到输入结束符(EOF)时,使用

try - except

语句捕获

EOFError

异常并跳出循环。

8、编写一个程序,逐行读取字符串列表,直到输入结束。然后,它应该按代码点顺序打印这些字符串。也就是说,如果你输入字符串 fred、barney、wilma、betty,输出应该显示 barney betty fred wilma。输出中的所有字符串是在一行上还是分行显示?你能让输出以这两种样式呈现吗?

如果想让输出在一行上,代码如下:


chomp(@lines = <STDIN>);
@sorted = sort @lines;
print "@sorted
";

若要分行显示,可去掉

chomp

去掉对换行符的处理,直接打印排序后的数组元素,如:


@lines = <STDIN>;
@sorted = sort @lines;
foreach my $line (@sorted) {
    print $line;
}

9、编写一个名为total的子程序,它返回一个数字列表的总和。该子程序不应执行任何输入/输出操作,只需处理其参数并将一个值返回给调用者。编写一个示例程序来测试这个子程序,示例程序中定义一个数组my @fred = qw{ 1 3 5 7 9 }; 调用total子程序计算该数组元素的总和并输出结果,结果应为25。同时,程序还应从标准输入读取一些数字(每行一个数字),调用total子程序计算这些数字的总和并输出结果。注意,在列表上下文中使用

将等待你以适合你系统的方式结束输入。

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


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

10、编写一个程序来计算 1 到 1000 这些数字的总和,假设存在一个子程序 total 用于计算列表中数字的总和。

实现该功能的程序示例如下:


# Remember to include &total from previous exercise!
print "The numbers from 1 to 1000 add up to ", total(1..1000), ".
";

其中

total

子程序需提前定义,用于计算列表中数字的总和。

11、编写一个名为 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)

“;

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


sub average {
    if (@_ == 0) {
        return
    }
    my $count = @_;
    my $sum = total(@_);
    $sum / $count;
}

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

其中,需要额外实现一个

total

子程序,用于计算数字列表的总和。

12、编写一个名为 greet 的子程序,通过告知被问候者上一个被问候者的名字来欢迎他们:执行 greet( “Fred” ); greet( “Barney” ); 这两条语句应输出:Hi Fred! You are the first one here! Hi Barney! Fred is also here!


use v5.10;

sub greet {
    state $last_person;
    my $name = shift;
    print "Hi $name! ";
    if( defined $last_person ) {
        print "$last_person is also here!
";
    } else {
        print "You are the first one here!
";
    }
    $last_person = $name;
}

greet( 'Fred' );
greet( 'Barney' );

13、修改程序,让它能告诉每个新来的人之前所有被问候过的人的名字。执行以下语句序列: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


使用v5.10版本及以上的Perl语言,代码如下:

```perl
use v5.10;
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;
}

14、编写一个程序,其功能类似于 cat 命令,但要将输出行的顺序反转。(有些系统有一个类似的实用工具名为 tac)。如果你以 ./tac fred barney betty 运行该程序,输出应该是文件 betty 的所有行按从最后一行到第一行的顺序,接着是 barney 的,然后是 fred 的,同样按从最后一行到第一行的顺序。(如果你将程序命名为 tac,调用时一定要使用 ./ ,以免调用到系统自带的实用工具)

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


import sys
for filename in reversed(sys.argv[1:]):
    try:
        with open(filename, 'r') as file:
            lines = file.readlines()
            for line in reversed(lines):
                print(line.rstrip())
    except FileNotFoundError:
        print(f"文件 {filename} 未找到。")

将上述代码保存为

tac.py

,然后在命令行中使用

python tac.py fred barney betty

来运行程序。如果要实现和题目中一样的调用方式,需要将代码保存为

tac

并赋予执行权限,然后使用

./tac fred barney betty

调用。

15、编写一个程序,要求用户在不同的行上输入一系列字符串,将每个字符串右对齐打印在一个20字符宽的列中。为确保输出在正确的列中,同时打印一行数字作为“标尺线”(这只是一个调试辅助工具)。确保不要误使用19字符宽的列!例如,输入hello、good – bye,输出应类似如下:123456789012345678901234567890123456789012345678901234567890


          hello
      good - bye

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


print "Enter some lines, then press Ctrl-D:
"; # or Ctrl-Z
chomp(my @lines = <STDIN>);
print "1234567890" x 7, "12345
"; # ruler line to column 75
foreach (@lines) {
    printf "%20s
", $_;
}

16、修改之前的程序,让用户选择列宽,这样输入 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
", $_;
}

或者使用:


foreach (@lines) {
    printf "%*s
", $width, $_;
}

17、编写一个程序,要求用户输入一个名字,并输出对应的姓氏。名字和姓氏的对应关系如下: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;

# 获取对应的姓氏
my $family_name = $name_map{lc $given_name};

# 输出结果
if ($family_name) {
    print "对应的姓氏是: $family_name
";
} else {
    print "未找到对应的姓氏。
";
}

18、编写一个程序,逐行读取一系列单词,直到输入结束,然后输出每个单词出现的次数总结。例如,如果输入的单词是 fred、barney、fred、dino、wilma、fred(每行一个单词),输出应表明 fred 出现了 3 次。额外加分项:按代码点顺序对输出的总结单词进行排序。

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


my(@words, %count, $word);
chomp(@words = <STDIN>);
foreach $word (@words) {
    $count{$word} += 1;
}
foreach $word (sort keys %count) {
    print "$word was seen $count{$word} times.
";
}

19、修改一个程序,使其也能匹配“Fred”。判断当输入字符串是“Fred”、“frederick”或“Alfred”时,程序是否能匹配。(假设可以在文本文件中添加包含这些名称的行)

修改方法是将之前程序中使用的模式改为

/[fF]red/

,也可以尝试

/(f|F)red/


/fred|Fred/

,但字符类更高效。

对于输入字符串:

– “Fred” 能匹配

– “frederick” 不匹配(当前逻辑)

– “Alfred” 中 “fred” 会匹配(当前逻辑)

注意:当前版本中要求匹配全词的功能尚未实现。后续会学习实现该功能,以修正“frederick”和“Alfred”的匹配行为。

20、编写一个程序,对文本文件进行修改并生成副本。在副本中,每个字符串 Fred(不区分大小写)应替换为 Larry。(例如,Manfred Mann 应变为 ManLarry Mann。)输入文件名应在命令行中给出(不要询问用户),输出文件名应为对应的以 .out 结尾的文件名。


my $in = $ARGV[0];
if (! defined $in) {
    die "Usage: $0 filename";
}
my $out = $in;
$out =~ s/(.w+)?$/.out/;
if (! open $in_fh, '<', $in ) {
    die "Can't open '$in': $!";
}
if (! open $out_fh, '>', $out ) {
    die "Can't write '$out': $!";
}
while (<$in_fh>) {
    s/Fred/Larry/gi;
    print $out_fh $_;
}

21、编写一个程序,该程序会反复要求用户猜测一个1到100之间的秘密数字,直到用户猜对为止。程序应使用神奇公式 int(1 + rand 100) 随机选取数字。当用户猜错时,程序应回应“Too high”或“Too low”。如果用户输入“quit”或“exit”,或者输入空行,程序应退出。当然,如果用户猜对了,程序也应退出!

以下是对应的 Perl 代码:


my $secret = int(1 + rand 100);
while (1) {
    print "Please enter a guess from 1 to 100: ";
    chomp(my $guess = <STDIN>);
    if ($guess =~ /quit|exit|As*z/i) {
        print "Sorry you gave up. The number was $secret.
";
        last;
    }
    elsif ($guess < $secret) {
        print "Too low. Try again!
";
    }
    elsif ($guess == $secret) {
        print "That was it!
";
        last;
    }
    else {
        print "Too high. Try again!
";
    }
}

22、修改一个程序,使其在运行过程中打印额外的调试信息,比如它选择的秘密数字。进行修改,以便可以关闭该调试信息输出,并且当关闭时程序不会发出警告。如果你使用的是 Perl 5.10 或更高版本,使用 // 运算符。否则,使用条件运算符。


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

使用 Perl 5.10 或更高版本:

```perl
use v5.10;
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;

23、编写一个程序,找出命令行中指定的最旧的文件,并报告其存在的天数。如果文件列表为空(即命令行中未提及任何文件),程序会怎样?

如果文件列表为空,程序会报错,提示没有提供文件名,因为没有文件可供检查,也就不存在最旧的文件。示例代码如下:


die "No file names supplied!" unless @ARGV;

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

以下是一个使用Perl编写的示例程序来实现该功能:


#!/usr/bin/perl
use v5.10;

foreach my $filename (@ARGV) {
    if (-r -w -o $filename) {
        print "$filename 是可读、可写且归你所有的文件。
";
    }
}

将上述代码保存为一个文件(例如

test.pl

),然后在命令行中运行,例如:


perl test.pl file1 file2 file3

程序将列出所有可读、可写且归当前用户所有的文件。

© 版权声明

相关文章

暂无评论

none
暂无评论...