4.3 perl--正则表达式处理文本
如果m//模式匹配现象成文字处理器的“查找”功能,那么s///替换操作符就是“查找并替换”功能。
$_="green scaly dinosaur";
s/(\w+)(\w+)/$2,$1/g; #替换后为“scaly,green dinosaur”
上面的例子中/g为全局替换。我们在缩减空白的时候,可以这么做:
s/^s+// ; #将开头的空白替换成空字符串
s/s+$//; #将结尾的空白替换为空字符串
也可以这么写:
s/^\s+|\s+$//g; 去除开头和结尾的空白符
s///也可以采用不同的定界符,但是如果是有左右之分的话,就必须成对使用。比如s{fred}{barney} 同时我们也可以使用之前提到的修饰符,顺序无限后,比如/i,/x,/s
下面是正则表达式中的一些常用模式。
/pattern/ 结果
. 匹配除换行符以外的所有字符
x? 匹配 0 次或一次 x 字符串
x* 匹配 0 次或多次 x 字符串,但匹配可能的最少次数
x+ 匹配 1 次或多次 x 字符串,但匹配可能的最少次数
.* 匹配 0 次或一次的任何字符
.+ 匹配 1 次或多次的任何字符
{m} 匹配刚好是 m 个 的指定字符串
{m,n} 匹配在 m个 以上 n个 以下的指定字符串
{m,} 匹配 m个 以上 的指定字符串
[] 匹配符合 [] 内的字符
[^] 匹配不符合 [] 内的字符
[0-9] 匹配所有数字字符
[a-z] 匹配所有小写字母字符
[^0-9] 匹配所有非数字字符
[^a-z] 匹配所有非小写字母字符
^ 匹配字符开头的字符
$ 匹配字符结尾的字符
\d 匹配一个数字的字符,和 [0-9] 语法一样
\d+ 匹配多个数字字符串,和 [0-9]+ 语法一样
\D 非数字,其他同 \d
\D+ 非数字,其他同 \d+
\w 英文字母或数字的字符串,和 [a-zA-Z0-9] 语法一样
\w+ 和 [a-zA-Z0-9]+ 语法一样
\W 非英文字母或数字的字符串,和 [^a-zA-Z0-9] 语法一样
\W+ 和 [^a-zA-Z0-9]+ 语法一样
\s 空格,和 [\n\t\r\f] 语法一样
\s+ 和 [\n\t\r\f]+ 一样
\S 非空格,和 [^\n\t\r\f] 语法一样
\S+ 和 [^\n\t\r\f]+ 语法一样
\b 匹配以英文字母,数字为边界的字符串
\B 匹配不以英文字母,数值为边界的字符串
a|b|c 匹配符合a字符 或是b字符 或是c字符的字符串
abc 匹配含有 abc 的字符串
(pattern) () 这个符号会记住所找寻到的字符串,是一个很实用的语法。第一个 () 内所找到的字符串变成 $1 这个变量或是 \1 变量,第二个 () 内所找到的字符串变成 $2 这个变量或是 \2 变量,以此类推下去。
/pattern/i i 这个参数表示忽略英文大小写,也就是在匹配字符串的时候,不考虑英文的大小写问题。
\ 如果要在 pattern 模式中找寻一个特殊字符,如 "*",则要在这个字符前加上 \ 符号,这样才会让特殊字符失效
下面给出一些例子:
范例 说明
/perl/ 找到含有 perl 的字符串
/^perl/ 找到开头是 perl 的字符串
/perl$/ 找到结尾是 perl 的字符串
/c|g|i/ 找到含有 c 或 g 或 i 的字符串
/cg{2,4}i/ 找到 c 后面跟着 2个到 4个 g ,再跟着 i 的字符串
/cg{2,}i/ 找到 c 后面跟着 2个以上 g ,再跟着 i 的字符串
/cg{2}i/ 找到 c 后面跟着 2个 g,再跟着 i 的字符串
/cg*i/ 找到 c 后面跟着 0个或多个 g ,再跟着 i 的字符串,如同/cg{0,1}i/
/cg+i/ 找到 c 后面跟着一个以上 g,再跟着 i 的字符串,如同/cg{1,}i/
/cg?i/ 找到 c 后面跟着 0个或是 1个 g ,再跟着 i 的字符串,如同/cg{0,1}i/
/c.i/ 找到 c 后面跟着一个任意字符,再跟着 i 的字符串
/c..i/ 找到 c 后面跟着二个任意字符,再跟着 i 的字符串
/[cgi]/ 找到符合有这三个字符任意一个的字符串
/[^cgi]/ 找到没有这三个字符中任意一个的字符串
/\d/ 找寻符合数字的字符,可以使用/\d+/来表示一个或是多个数字组成的字符串
/\D/ 找寻符合不是数字的字符,可以使用/\D+/来表示一个或是更多个非数字组成的字符串
/\*/ 找寻符合 * 这个字符,因为 * 在常规表达式中有它的特殊意思,所以要在这个特殊符号前加上 \ 符号,这样才会让这个特殊字符失效
/abc/i 找寻符合 abc 的字符串而且不考虑这些字符串的大小写
无损替换
(my $copy =$original)=^s/\d+ribs?/10 ribs/;
也可以在修饰符r的作用下这么使用
use 5014;
my $copy =$original=^s/\d+ribs?/10 ribs/r;
大小写的转换:
\U 将其后的所有字符转换成大写
\L 将后面的所有字符转换成小写
\E 关闭大小写的功能
\l \u 小写的形式仅仅影响后面跟的第一个字符
\u\L 表示首字母大写,后面的字符全部小写,顺序无先后
例子: s/(\w+) with (\w+)/\U$2\E with $1/i; 这个例子中仅仅对$2大写,其后的不变。
split操作符
根据模式来拆分字符串;
my @fields =split /separator/,$string;
期间只要模式在某处匹配成功,该处就是当前字段的结尾,下一个字段的开头。
my @fields =split /:/,"abc:def:g:h"; #得到的是("abc","def","g","h")
如果是两个分隔符在一起,就会产生空字段,保留开头处的空字段,舍弃结尾处的空字段。
my @fields =split #等效于my @fields =split /\s+/,$_;
join函数
它的功能和split相反,它可以把这些片段连接成一个字符串
my $result= join $glue,@pieces;
例如
my $x=join ":",4,6,8,10,12; # $x为“4:6:8:10:12”
在列表上下文中使用模式匹配操作符(m//)时,如果匹配成功,那么返回的是所有捕获变量的列表;如果匹配失败,则返回的是空列表
my $data ="Barney Rubble Fred Flintstone Wilma Flintstone"
my @words=($data=~/(\w+)\s+(\w+)/g);
my $words=($data=~/(\w+)\s+(\w+)/g);
你看 ,这样就可以将标量变成数组或哈希了。
I thought you said Fred and Velma,notWilma
可以这样来 s#(.*?)#$1#g; 如果不加问号的话,就只有一个结果,加了以后才能有两个
把整个文件读进一个变量,然后把文件名作为每一行的前缀。
open FILE,$filename
or die "Can't open '$filename':$!";
my $lines=join '',;
$LINES=~s/^/$filename:/gm;
从命令行直接编辑
在终端中输入 :
$perl -p -i.bak -w -e 's/RANDALL/RANDAL/g' fred*.dat
这个就相当于:
#! /usr/bin/perl -w
$^I=".bak";
while(<>){
s/RANDALL/RANDAL/g;
print;
}
-p让perl自动生成一段小程序, -i相当于$^I设为.bak,如果不想备份文件的话,可以直接写-i;-w警告功能;-e后面跟着的是可执行的程序代码
例1:匹配3个$what
#! /usr/bin/perl
use warnings;
use strict;
my $what='fred|barney';
while (<>){
chomp;
if (/($what){3}/){
print "$_\n";
}
}
例2:将Fred换成Larry,同时输出文件名为*.out
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
chomp;
s/Fred/Larry/ig;
print "$_\n";
}
根据上面的程序即可,同时在使用的时候 : perl 程序名 <文件名> 生成的文件名.out 当然也可以指定输出,但是我觉得太麻烦了,就算了吧
例3:将Fred和Barney互换
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
chomp;
s/Fred/Larry/ig;
s/barney/Fred/ig;
s/Larry/Barney/ig;
print "$_\n";
}
例4:在开始前加文本申明:
#! /usr/bin/perl
use warnings;
use strict;
$^I=".bak";
while(<>){
s/\A\#/## Copyright (C) 2013 by Sam \n\#/;
print;
}
参考资料:
- 夕岚一瞥 http://blog.sina.com.cn/s/blog_60f9c00501016igo.html
- Randal L 《Perl语言入门》
ps:
- 上面的方法尽管参考,方法肯定不止一个
- 如果跟我一样是菜鸟,请结合我的第之前的博客看如何运行这样的脚本。
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn