Chinaunix首页 | 论坛 | 博客
  • 博客访问: 837513
  • 博文数量: 253
  • 博客积分: 6891
  • 博客等级: 准将
  • 技术积分: 2502
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-03 11:01
文章分类

全部博文(253)

文章存档

2016年(4)

2013年(3)

2012年(32)

2011年(184)

2010年(30)

分类: Python/Ruby

2011-07-26 09:43:31

可以通过正则表达式来改变文本。到目前为止,只介绍过怎么匹配模式。现在,我们将向你演示怎样通过模式来改变字符串中相应地部分。

使用s///进行替换
  1. my $string = "this is a bag.";
  2. $string =~ s/this/This/;
  3. print $string;

  4. This is a bag.
如果没有匹配上,则什么也不会发生,此变量也不会有任何更改:
模式和被替换的字符串可能更复杂。下例中,替换的字符串使用了变量:$1,其值由模式匹配所赋值:
  1. $_ = "He's out bowling with Fred tonight";
  2. s/with (\w+)/against $1's team/;
  3. print "$_\n";

  4. He's out bowling against Fred

  1. $_ =“green scaly dinosaur”;
  2.     s/(\w+) (\w+)/$2, $1/; #现在为“scaly, green dinosaur”;
  3.     s/^/huge, /; #现在为“huge, scaly, green dinosaur”
  4.     s/,.*een//; #空替换,现在为“huge dinosaur”
  5.     s/green/red/; #匹配失败,仍然为“huge dinosaur”
  6.     s/\w+$/($`!)$& /; #现在为“huge (huge !)dinosaur”
  7.     s//\s+(!\W+)/$1 /; #现在为“huge ( dinosaur”
  8.     s/huge/gigantic/; #现在为“gigantic ( dinosaur”



  9. s///会返回一个Boolean 值。如果成功替换则返回true;否则返回false:
  10. $_ = “fred flintstone”;
  11. if(s/fred/wilma/){
  12. print “Successfully replaced fred with wilma!\n”;
  13. }
使用/g 进行全局替换
  1. $_ = “home, sweet home!”;
  2. s/home/cave/g;
  3. print “$_\n”; # “cave, sweet cave!”;

  4. 全局替换的一个常用地方是将多个空格用单个空格替换掉
  5. $_ =“Input data\t may have extra whitespace.
  6. s/\s+/ /g; #现在是“Input data may have extra whitespace.

  s/^\s+|\s+$//g; #将开头,结尾的空白去掉

不同的分隔符
如同m//和qw//一样,我们也可以改变s///的分隔符。但这里使用了3个分隔符,因此有些不同。通常的(非配对的)字符,由于没有左字符和右字符的区别,则可以像使用正斜线(/)那样使用。如,使用井号(#)◆作为分隔符:s#^
如果使用的是配对的字符,也就是说其左字符和右字符不的,则必需使用两对:一对存放模式,一对存放替换的字符串。此时,分隔符甚至可以是不同的。事实上,分隔符还可以使用普通的符号(非配对的)。下面三例是等价的:
s{fred}{barney};s[fred](barney);s#barney#;

可选的修饰符
替换操作中还可以使用/i, /x, 和/s,这些在普通的模式匹配中已经出现过的修饰符。其顺序是无关紧要的。
s#wilma#Wilma#gi; #将所有的WilmA,或者WILMA 等等,由Wilma 替换掉
s{_ _END_ _.*}{ }s; #将END 标记及其后面的行去掉

大小写转换
\U 要求紧接着的均是大写,,也可以要求后面的均为小写:\L:
  1. $_ = "I saw Barney with Fred.";
  2. s/(fred|barney)/\U$1/gi;
  3. s/(fred|barney)/\L$1/gi;

  4. #$_现在是“I saw BARNEY with FRED.
  5. #$_现在是“I saw barney with fred.
默认时,会影响到剩余的(替换的)字符串。可以使用\E 来改变这种影响:
s/(\w+) with (\w+)/\U$2\E with $1/i;    #$1 现在是“I saw FRED with barney.”

使用小写形式时(\l 和\u),只作用于下一个字符:
s/ (fred|barney)/\u$1/ig; #$_现在是“I saw FRED with Barney.”
也可以同时使用它们。如使用\u 和\L 表示“第一个字母大写,其它字母均小写
s/(fred|barney)/\u\L$1/ig; #$_现在为“I saw Fred with Barney.”

split 操作
其形式如下:@fields = split /separtor/, $string;
@fields = split /:/, “abc:def:g:h”; #返回(“abc”, “def”, “g”, “h”)
可能得到空的元素,如果其中有两个分隔符是连在一起的:
@fields = split /:/,“abc:def::g:h”; #得到(“abc”, “def”, “”, “g”, “h”)
my $some_input = “This is a \t test.\n”;
my @args = split /\s+/, $some_input; #(“This”, “is”, “a”, “test.”)
默认时,split 对$_操作,模式为空白:my @fields = split; #同split /\s+/, $_;

join 函数
join 函数不使用模式,但它完成同split 相反的操作:split 将一个字符串分割开,而join 函数将这些分割的部分组合成一个整体。join 函数类似于:
my $result = join $glue, @pieces;
join 函数的第一个参数是粘合元素(glue),它可以是任意字符串。剩下的参数是要被粘合的部分。
。join 将粘合元素添加在这些部分之间,并返回其结果:
my $x = join“:”, 4, 6, 8, 10, 12; #$x 为“4:6:8:10:12”

列表上下文中的m//
  1. my $text = “Fred dropped a 5 ton granite block on Mr. Slate”;
  2. my @words = ($text =~ /([a-z]+)/ig);
  3. print “Result: @words\n”;
  4. #Result: Fred dropped a ton granite block on Mr slate
非贪婪的数量词
:假设在fred and barney went bowling last night 上使用/fred.+barney/进行匹配
首先,子模式fred 将匹配其对应的字符串。模式的下一部分是.+,它将匹配除了换行符之外的任意字符,次数大于等于一。。但,由于加号(+)是贪婪的;它将尽可能的进行匹配。因此,它将匹配剩余的所有字符串,包括night。现在对banrey 进行匹配,但不能成功,因为已经到了字符串的结尾处。由于.+在少一个字符的情况下仍能匹配成功,因此它退回字符串最后一个字母t。子模式barney 又尝试匹配,结果仍是不行。因此.+再退回字母h,又进行匹配。正则表达式引擎有大量的像上面那样的回退(backtracking)操作,尝试每一种可能,直到成功或者根本不能匹配为止。因此对于每一个贪婪的数量词,需要一种非贪婪的方法。不是使用加号(+),而是使用非贪婪的数量词+?,它将匹配一次或多次(加号的意思),但其匹配尽可能少的次数,而非尽可能多的次数。现在我们来看看模式为/fred.+?barney/时的过程。首先,fred 将被匹配上。接着,模式的下一部分是.+?,它匹配的字符个数不大于1,因此匹配fred 后面的空格。下一个子
模式是banrey,它在这里不能被匹配(因为现在的位置是and barney… 的开头)。.+?再匹配a,剩下的模式继续进行匹配。又一次,barney 不能匹配上,

由于加号的非贪婪类型是+?,星号的为*?,你可能已经意识到剩下的两种数量词其对应的类型也是类似的。花括号的非贪婪类型看起来一样,只是在闭花括号后有一个问号,如{5,10}?或者{8,}?◆。甚至问号数量词也有非贪婪类型:??。它匹配一次或者0 次,但倾向于匹配0 次。

匹配多行文本
/m 这个正则表达式选项允许它们根据内部的换行符进行匹配。
  1. $_ = "i am much better\nthan Barney is\nat bowling,\nWilma,\n";
  2. print "Found wilma at start of line\n" if /^wilma\b/im;
在下面的例子中,我们将整个文件读入一个变量之中◆,然后将文件名字加在每一行的开头处:
  1. open FILE, $filename
  2. or die “Can’t open ‘$filename’: $!;
  3. my $lines = join '', <FILE>;
  4. $lines =~ s/^/$filename: /gm;
更新大量文件
  1. #! /usr/bin/perl –w
  2. use strict;
  3. chomp(my $date = `date`);
  4. $^I =.bak”;
  5. while(<>){
  6. s/^Author:.*/Author: Randal L. Scharwartz/;
  7. s/^Phone:.*\n//;
  8. s/^Date:.*/Date: $date/;
  9. print;
  10. }
我们需要在3 个地方进行修改。作者(Author)的名字需要更改,日期(Date)需要更新,电话(Phone)需要删除。
由于需要当前的日期,因此在程序开端使用了系统命令:date。另一种获得时间的更好的方法是(格式有些不同)使用Perl自带的localtime 函数,其在标量context 中使用:
my $date = localtime;
$^I。默认时为undef,此时没有什么特殊的地方。但给它设置某些串时,它使尖括号操作(<>)变得有些特殊。我们知道尖括号(<>)的神奇特点:如果没有指定文件名,则其从标准输入流中自动打开和关闭一系列文件进行读入。但如果$^I 中有字符串,这个字符串则会成为备份文件的扩展名。我们在下面仔细讨论。我们假设此时尖括号(<>)打开的文件是fred03.dat。它像以前那样打开它,但进行了重名名,把它叫做fred03.dat.bak。现在<>将这个新的文件作为默认的输出,因此任何内容将输出到那个文件中。Perl 修改我的文件fred03.dat,做了我希望的修改,并将早期的文件保存在叫做fred03.dat.bak 的文件之中

在命令行中进行修改
$perl –p –i.bak –w –e ‘s/Randall/Randal/g’fred*.dat
-p:要求Perl 为你写一个程序。
-i:它在程序开始处将$^ I 的值设置为“.bak”。
-w:作用是将警告打开。
-e:“执行下面的代码。”即是说s/Randall/Randal/g 字符串被当作Perl 代码执行。
最后一个参数是fred*.dat,它指定@ARGV 应当包含匹配上此模式的文件名。这几部分综合起来,就是一个大致如下的程
序,输入为匹配上fred*.dat 的文件:
#! /usr/bin/perl –w
$^I =“.bak”;
while(<>){
s/Randall/Randal/g;
print;
}

非捕捉用的括号
如果只想用括号将某部分进行分组,并不想将它们存入变量之中。。我们在开括号后面加上一个问号和冒号,(?:)。其作用事告诉Perl 括号只是分组的作用。
您没有插入代码
  1. $_ = "this is bronoto status steak";
  2. if(/(?:bronto)?status (steak)/){
  3.     print "found $1\n";
  4. }





阅读(523) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~