Perl-用正则表达式处理文本3

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;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值