1. join函数
join函数不使用模式,join会把片段结合成1个字符串
my $result = join $glue, @pieces;
join的第1个参数可以理解成胶水,它可以是任意字符串
第2个参数是一串字符串片段,join会把胶水涂进每个片段之间并返回结果字符串
my $x = join ":", 4, 6, 8, 10, 12; # $x 为“4:6:8:10:12”
胶水只在2个片段中间出现,不在之前也不在其后,所以胶水的层数会比列表中的条目数少1个。这意味着列表至少要有2个元素,否则胶水涂不进去。
my $y = join "foo", "bar"; # 只有1个“bar”, 这里不会起作用
my @empty; # 空数组
my $empty = join "baz", @empty; # 没有元素,所以得到一个空的字符串
使用上面的$x
,我们可先分解字符串,再用不同的定界符将它接起来
my @values = split /:/, $x; # @values为(4, 6, 8, 10, 12)
my $z = join "-", @values; # $z 为 "4-6-8-10-12"
2. 列表上下文中的m//
在列表上下文中使用模式匹配操作符m//
时,如果模式匹配成功,那么返回的是所有捕获变量的列表,如果匹配失败,则会返回空列表
$_ = "Hello there, neighbor!";
my ($first, $second, $third) = /(\S+) (\S+), (\S+)/;
print "$second is my $third\n";
代码中没有用到=~
绑定操作符,所以该模式匹配默认是针对$_
进行的
my $text = "Fred dropped a 5 ton granite block on Mr. Slate";
my @words = ($text =~ /([a-z]+)/ig);
print "Result:@words\n"; # Result: Fred dropped a ton granite block on Mr Slate
这像是split操作符的逆功能:正则模式指定的是要留下来的部分
如果模式中有多组圆括号,那么每次匹配就能捕获多个字符串,我们可以把一个字符串变成哈希
my $text = "Barney Rubble Fred Flintstone Wilma Flintstone";
my %last_name = ($text =~ /(\w+)\s+(\w+)/g); # 每次模式匹配成功,就会返回一对被捕获的值,而这一对值正好成为新哈希的键-值对
3. 更强大的正则表达式
1. 非贪婪量词
目前为止,看到的量词都是贪婪(greedy)量词,它们按照左起最长原则尽可能多地匹配文本,但有时候匹配范围过宽
my $text = '<b>Fred</b> and <b>Barney</b>'; # 我们想把位于标签之间的名字都改成全大写版本
$text =~ s|<b>(.*)</b>|<b>\U$1\E</b>|g; # 这里只有1个捕获变量
print "$text\n"; # <b>FRED</B> AND <B>BARNEY</b>
由于.*
属于贪婪匹配,它会从第1个<b>
开始一直匹配到最后1个</b>
为止,不过我们想要的是从<b>
到下一个</b>
之间地部分。这是用正则表达式解析HTML源代码经常会遇到的问题
在量词后加上?
,就会在第一次找到合适的位置是结束
my $text = '<b>Fred</b> and <b>Barney</b>';
my $match_count = $text =~ s|<b>(.*?)</b>|\U$1|g; # 不贪婪
print "$match_count: $text\n"; # FRED and BARNEY
使用非贪婪量词后,正则表达式不会1次找到底再逐步回退这样去浪费时间,它直接找最接近的符合条件的部分
元字符 | 意义 |
---|---|
?? | 匹配0个字符(其实没啥用) |
*? | 0个或多个,越短越好 |
+? | 1个或多个,越短越好 |
{3, }? | 至少3个,越短越好 |
{3, 5}? | 至少3个,最多5个,不过还是越短越好 |
{3}? | 正好3个 |
2. 更别致的单词边界符
my $string = "This doesn't capitalize correctly.";
$string =~ s/\b(\w)/\U$1/g;
print "$string"; # This Doesn'T Capitalize Correctly.
在perl的定义中,单词字符不包括单引号,所以单引号字符2侧都能匹配交替边界
perl 5.22开始增加了基于unicode规范的新单词边界,这个边界符会探视周围猜测最符合语义的单词开始和结束位置
use v5.22;
my $string = "this doesn't capitalize correctly.";
$string =~ s/\b{wb}(\w)/\U$1/g;
print "$string\n"; # This Doesn't Capitalize Correctly
新的\b{wb}
比较聪明,它会觉得单引号后的t不是独立单词,应该和之前的部分一起成为1个单词
还有一个新的单词边界符\b{sb}
,它按照一系列规则推断某个标点符号是句子的末尾,还是类似“Mr. Flintstone”这样用在缩略语中的一部分
perl 5.24还增加了一个行边界符,以此推断合理的行与行之间的边界,避免换行时打断某个单词,或在单词内的标点符号处换行,或在其它不该换行的空格处换行。行边界符\b{lb}
知道如何在正确的句子末尾塞入1个换行符
$string =~ s/(.{50, 75})\b{lb}/$1\n/g;