Skip to content

Perl 数组

在 Perl 中,数组 (array) 是一个有序的标量值 (scalar values) 列表。数组变量名以符号 @ 作为前缀。要访问数组的单个元素,需要使用符号 $ 加上数组名,后跟方括号 [] 中的元素索引 (index),例如 $array[0]。

在 Perl 脚本的开头使用 use strict; 和 use warnings; 是标准做法,这有助于进行更好的错误检查和提高代码质量。

数组声明和访问示例:

#!/usr/bin/perl
use strict;
use warnings;
my @ages = (25, 30, 40);
my @names = ("John Paul", "Lisa", "Kumar");
print "Ages[0]: $ages[0]\n"; # 输出: Ages[0]: 25
print "Ages[1]: $ages[1]\n"; # 输出: Ages[1]: 30
print "Names[1]: $names[1]\n"; # 输出: Names[1]: Lisa
# 打印数组的所有元素
print "All names: @names\n"; # 输出: All names: John Paul Lisa Kumar

在 Perl 中,“list” (列表) 指的是有序的数据集合本身,而 “array” (数组) 则是用于存储这种列表的变量。

创建数组通常使用括号 (),或者使用 qw// (quote word) 运算符来创建简单的字符串列表。

my @numbers = (1, 2, 3, 4, 5);
my @strings = ('apple', 'banana', 'cherry');
# 使用 qw// 创建单词列表(自动加引号并按空白字符分割)
my @weekdays = qw(Mon Tue Wed Thu Fri Sat Sun);
# 等价于: my @weekdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
# qw 也可以使用其他分隔符:
my @colors = qw!red green blue!;
my @symbols = qw#alpha beta gamma#;

也可以创建一个空数组:my @empty_array = ();

数组索引从 0 开始。也可以使用负数索引从数组末尾访问元素(-1 是最后一个元素,-2 是倒数第二个,依此类推)。

#!/usr/bin/perl
use strict;
use warnings;
my @days = qw(Mon Tue Wed Thu Fri Sat Sun);
print "First day: $days[0]\n"; # 输出: First day: Mon
print "Third day: $days[2]\n"; # 输出: Third day: Wed
print "Last day: $days[-1]\n"; # 输出: Last day: Sun
print "Second to last: $days[-2]\n"; # 输出: Second to last: Sat

Perl 的范围运算符 .. 可以用来创建顺序的数字或字母数组。

#!/usr/bin/perl
use strict;
use warnings;
my @first_ten = (1..10); # (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
my @some_letters = ('a'..'f'); # ('a', 'b', 'c', 'd', 'e', 'f')
print "Numbers: @first_ten\n";
print "Letters: @some_letters\n";

要获取数组中的元素数量,可以在标量上下文 (scalar context) 中评估该数组。

my @my_array = (10, 20, 30);
my $size = @my_array; # $size 是 3
print "Array size: ", scalar(@my_array), "\n"; # 另一种强制使用标量上下文的方法
print "Array size: $#my_array + 1\n"; # $#array 返回最后一个索引

$#array_name 返回 @array_name 中最后一个元素的索引。因此,数组的大小是 $#array_name + 1。如果数组为空,$#array_name 是 -1。

Perl 提供了用于在数组开头或末尾添加/移除元素的函数:

函数描述
push @ARRAY, LIST将 LIST 的元素附加到 @ARRAY 的末尾。返回新的元素数量。
pop @ARRAY移除并返回 @ARRAY 的最后一个元素。
unshift @ARRAY, LIST将 LIST 的元素添加到 @ARRAY 的开头。返回新的元素数量。
shift @ARRAY移除并返回 @ARRAY 的第一个元素。
#!/usr/bin/perl
use strict;
use warnings;
my @fruits = qw(apple banana);
print "Initial: @fruits\n";
push @fruits, 'orange', 'grape';
print "After push: @fruits\n"; # apple banana orange grape
my $last_fruit = pop @fruits;
print "Popped: $last_fruit, Array: @fruits\n"; # grape, Array: apple banana orange
unshift @fruits, 'mango';
print "After unshift: @fruits\n"; # mango apple banana orange
my $first_fruit = shift @fruits;
print "Shifted: $first_fruit, Array: @fruits\n"; # mango, Array: apple banana orange

数组切片 (array slice) 允许你根据索引从数组中选择多个元素,形成一个新的列表(该列表可以赋值给另一个数组)。

#!/usr/bin/perl
use strict;
use warnings;
my @days = qw(Mon Tue Wed Thu Fri Sat Sun);
# 获取指定元素
my @work_days = @days[0, 1, 2, 3, 4]; # Mon Tue Wed Thu Fri
print "Work days: @work_days\n";
# 获取范围元素
my @mid_week = @days[1..3]; # Tue Wed Thu (索引 1, 2, 3)
print "Mid week: @mid_week\n";
# 切片可以使用任何有效索引,包括负数索引
my @ends = @days[0, -1]; # Mon Sun
print "Ends: @ends\n";

splice 函数在修改数组方面非常强大:它可以在特定位置移除元素、添加新元素,或者同时进行这两项操作。

splice @ARRAY, OFFSET, [LENGTH, [LIST]]
  • @ARRAY: 要修改的数组。
  • OFFSET: 修改的起始索引。负数偏移量从末尾开始计数。
  • LENGTH (可选): 从 OFFSET 开始要移除的元素数量。
  • LIST (可选): 在移除 LENGTH 个元素后,要插入到数组 OFFSET 位置的元素。

splice 返回从 @ARRAY 中移除的元素列表。

#!/usr/bin/perl
use strict;
use warnings;
my @letters = ('a'..'g'); # a b c d e f g
print "Original: @letters\n";
# 从索引 2 开始移除 2 个元素 ('c', 'd')
my @removed = splice @letters, 2, 2;
print "Removed: @removed, Array: @letters\n"; # Removed: c d, Array: a b e f g
# 重置以便进行下一个示例
@letters = ('a'..'g');
# 在索引 1 处移除 1 个元素 ('b') 并插入 'X', 'Y'
@removed = splice @letters, 1, 1, 'X', 'Y';
print "Removed: @removed, Array: @letters\n"; # Removed: b, Array: a X Y c d e f g
# 重置以便进行下一个示例
@letters = ('a'..'g');
# 在索引 3 处插入 'Z',不移除任何元素
splice @letters, 3, 0, 'Z';
print "Array after insert: @letters\n"; # a b c Z d e f g

split 函数根据分隔符模式 (delimiter pattern) 将一个字符串分割成子字符串列表。

split /PATTERN/, EXPR, [LIMIT]
#!/usr/bin/perl
use strict;
use warnings;
my $csv_data = "apple,banana,cherry,date";
my @fruits = split /,/, $csv_data;
print "Fruits: @fruits\n"; # Fruits: apple banana cherry date
my $sentence = "This is a sample sentence.";
# 按空白字符分割(如果省略 PATTERN 或 PATTERN 是 ' ',则为默认行为)
my @words = split /\s+/, $sentence; # 使用显式的空白字符模式
# my @words = split ' ', $sentence; # 用于按空白字符分割的常用写法
print "Words: @words\n"; # Words: This is a sample sentence.
# 限制分割次数
my $path = "/usr/local/bin/perl";
my @parts = split /\//, $path, 3; # 限制为 3 个部分(2 次分割)
print "Path parts: @parts\n"; # Path parts: usr local/bin/perl (由于开头的 /,第一个部分为空)

join 函数使用指定的分隔符字符串 (separator string) 将列表中的元素组合成一个字符串。

join SEPARATOR, LIST
#!/usr/bin/perl
use strict;
use warnings;
my @items = qw(one two three four);
my $joined_string = join '-', @items;
print "Joined with '-': $joined_string\n"; # Joined with '-': one-two-three-four
my $no_sep_string = join '', @items;
print "Joined with empty: $no_sep_string\n"; # Joined with empty: onetwothreefour

sort 函数对列表进行排序并返回排序后的列表。默认情况下,它按字母顺序(ASCII 顺序)排序。

sort [SUBROUTINE_OR_BLOCK] LIST
#!/usr/bin/perl
use strict;
use warnings;
my @names = qw(Alice Charlie Bob David);
my @sorted_names = sort @names;
print "Sorted names (alpha): @sorted_names\n"; # Alice Bob Charlie David
my @numbers = (10, 2, 100, 5, 25);
my @alpha_sorted_numbers = sort @numbers;
print "Sorted numbers (alpha): @alpha_sorted_numbers\n"; # 10 100 2 25 5 (不适合数字排序)
# 使用比较块进行数字排序
my @numerically_sorted_numbers = sort { $a <=> $b } @numbers;
print "Sorted numbers (numeric): @numerically_sorted_numbers\n"; # 2 5 10 25 100
# 逆序数字排序
my @reverse_numeric = sort { $b <=> $a } @numbers;
print "Sorted numbers (reverse numeric): @reverse_numeric\n"; # 100 25 10 5 2

在 sort 块内部,$a 和 $b 是特殊的包变量 (package variables),存储着正在比较的两个元素。如果 $a 排在 $b 前面,块应该返回 -1;如果它们相等,返回 0;如果 $a 排在 $b 后面,返回 1。飞船运算符 <=> 用于数字比较,cmp 用于字符串比较。

较旧版本的 Perl 有一个特殊变量 $[,可以改变数组的起始索引(默认为 0)。这个变量已被强烈弃用,且一直被强烈不推荐使用。它在 Perl 5.30 版本(于 2019 年发布)中被完全移除。**在现代 Perl 代码中不要使用 $[。**所有 Perl 数组都是从 0 开始索引的。

只需将多个数组包含在一个列表中,然后将该列表赋值给一个新的数组,就可以实现数组合并。

#!/usr/bin/perl
use strict;
use warnings;
my @odd = (1, 3, 5);
my @even = (2, 4, 6);
my @numbers = (@odd, @even, 7, 8);
print "Merged numbers: @numbers\n"; # 1 3 5 2 4 6 7 8
# 也可以直接嵌入列表字面量
my @mixed = (10, 20, (30, 40), 50);
print "Mixed: @mixed\n"; # 10 20 30 40 50

可以直接对列表字面量 (list literal)(即括号中的列表)应用数组索引和切片。

#!/usr/bin/perl
use strict;
use warnings;
my $third_element = (10, 20, 30, 40, 50)[2];
print "Third element from list: $third_element\n"; # 30
my @slice_from_list = (qw(a b c d e f))[1..3];
print "Slice from list: @slice_from_list\n"; # b c d