Perl 学习笔记-正则表达式处理文本
1.使用正则表达式替换文本 s///
s/<pattern>;/<replacement>;/ 如果匹配失败, 则什么也不会发生, 变量也不受影响. 返回布尔值, 替换成功时为真, 否则为假.
$roger = "This is a text"; $roger =~ s/This (\w+)/This was/; print $roger;
$_ = "green scaly dinosaur"; s/(\w+) (\w+)/$2, $1/; print; printf("\n"); #scaly, green dinosaur s/^/huge, /;print; printf("\n"); #huge, scaly, green dinosaur s/,.*een//;print; printf("\n"); #huge dinosaur s/green/red/; print; printf("\n"); #失败, 不会变 s/\w+$/($`!)$&/;print; printf("\n"); #huge (huge !)dinosaur s/\s+(!\W+)/$1 /;print; printf("\n"); #huge (huge!) dinosaur s/huge/gigantic/;print; printf("\n"); #gigantic (huge!) dinosaur
更换定界符: 无左右之分的字符(非成对),重复3次即可, 否则用2对, 一对圈引模式,一对圈引替换字符串. 圈引字符串定界符合圈引替换定界符不必相同, 如: s#roger#loger#; s{roger}{loger}; s[roger](loger); s<roger>#loger#;
2.使用/g进行全局替换
$_ = "roger, go on roger!"; s/roger/loger/g; #不重不漏替换所有匹配串 print ;
常用技巧
$_ = " This is a text that don't beatiful! "; s/\s+/ /g; #去掉多余的空白 print; printf("\n"); s/^\s+//; # 去掉前导空格 print; printf("\n"); s/\s+$//; # 去掉末尾空格 print; printf("\n");
使用修饰符修改大小写:
\U 将其位置后的所有字符转换成大写. \u 将位置后的第一个字符转换为大写
\L 将其位置后的所有字符转换成小学, \l 将位置后的第一个字符转换成小写.
3.split操作符
split使用正则表达式, 根据分隔符拆开一个字符串, 并返回对应的一个数组; 方便用来处理被制表符/冒号/空白/任意符号分隔的数据. 只要能将分隔符写成模式, 就可以用split提取数据.
用法: @fields = split /<pattern>/, $string; 如果两个分隔符连在一起, 就会产生空字段 ; split会保留开头的所有空字段并去掉结尾处的空字段(如果想要保留, 加上第3个参数并赋值为-1即可).
默认: 使用空白字符分割 $_ ; 相当于 split /\s+/,$_; 但不完全是, 因为它还会进一步省略开头的空字段.
4. join函数(胶水操作) -- split的逆操作
join不使用正则表达式, 将它的第一个参数(字符串,而不是模式)作为胶水, 粘接后面其他参数(变长参数)构成的片段. 胶水只会在片段之间使用.
5.列表上下文中的 m//
收到split的启发, 分隔符并非真正有用的数据字段, 在列表上下文中匹配时, 如果成功匹配, 可以返回所有捕获的变量的列表, 匹配失败, 返回空列表.
$_ = "Hello there, neighbor!"; @roger = /(\S+) (\S+), (\S+)/; print $roger[1]; #there
/g也可以用在m//上
# 将匹配的字符串按一前以后组成哈希, 如 Barney Rubble都匹配, 返回后Barney为键,Rubble为值 my $data = "Barney Rubble Fred Flintstone Wilma Flintstone"; my %last_name = ($data =~ /(\w+)\s+(\w+)/g); print $last_name{Wilma}."\n";
6.非贪婪量词
目前掌握的所有量词都是贪婪的, 会尽量匹配多的字符, 如果不满足才返回匹配少的 , 如 .* , 如果要使用非贪婪的量词,可以在量词后面加上一个 ? , 所以非贪婪量词就有以下这些: +? *? ?? {m,n}?
7.跨行的模式匹配
一般而言,Perl中的正则表达式用来匹配单行文本, 由于Perl可以处理任意长度的字符串, 所以一般没什么问题. 现在讨论处理多行文本.
表示多行文本: 在一个字符串中加上\n就表示多行文本, 但是匹配字符串首尾时并不会在意\n的存在, 因为 ^ 和 $ 匹配的是整个字符串的首尾. 要想考虑到\n的存在, 将字符串当做多行文本来处理, 就需要在模式后面加上 /m ,表示(multiple lines), 此时, ^ 和 $ 就表示匹配一样的首和尾.
open MYFILE, ">> a.txt" or die "Can't open file!\n"; $_ = "I'm much better\nthan Barney is\nat bowling,\nWilma.\n"; if(/^I'm.*?better$/m){ print MYFILE $&."\n"; #I'm much better } close MYFILE;
8.一次更新多个文件
获取本地时间, $date = localtime; 这个可以获取标准时间字符串, 如果直接打印localtime, 将得到时间戳. 也可以用系统的date命令, $date = `date`
在Perl中进行文件修改可以使用钻石操作符和特殊的变量 $^I
chomp(my $date = localtime); $^I = ".bak"; #这个变量的默认值为undef, 当被赋值为某个字符串时, 钻石操作符就会将自动打开的文件进行备份,后缀名加上变量的内容,需要注意的是如果这个变量为空, 就会直接修改原文件,数据可能会丢失 while(<>){ s/^Author:.*/Author: Roger/; #在这里对文件内容进行修改 # 将文本替换后输出到目标文件, 没有修改过的内容会被保留 print; #输出到对应的文件中, 可以认为是由钻石操作符来维护 }
9.命令行在线编辑 -- 对上一条的再简化
命令行中: $ perl -p -i.bak -w -e 's/Author:Roger.*/Author:Roger/g' a*.dat , 功能和上面相同.
-p 表示生成一段代码 while(<>){print;}
-i.bak 表示给变量 $^I赋值为 ".bak"
-w 表示打开警告
-e 表示有多条语句, 最后一条可省略分号;