随笔-314  评论-209  文章-0  trackbacks-0

 pattern比对    (grep)

字符串 命令 /pattern/修饰词
命令
=~          表示比對符合pattern
!~         表示比對不符合pattern
修饰词
i 不計大小寫
x 在模式中忽略空格
g 继续比对,继续寻找,相当于find next
   例子  :扫描文件gogo,找含有want的行
#!/usr/bin/perl

$file="/home/macg/perltest/gogo";
&gotest($file);

sub gotest{
my(@tmp)=@_;

open (MYFILE, $tmp[0]) || die ("Could not open file");
my($line,$newline);
while ($line=<MYFILE>) {
if($newline=($line=~/want/)) {          行中查找含有want 
  print "found\n";
  print "\$line is:$line";
  print "\$newline is:$newline \n";
 } else {
  print "not found\n";
  print "\$line is:$line";
  print "\$newline is:$newline \n";
    }
  }
close(MYFILE);
}    
 
[macg@localhost perltest]$ ./tip.pl
not found
$line is:I glad to be Los angle
$newline is:
found
$line is:I want to be Los angle
$newline is:1


    缺省的,模式定界符为反斜线/,但其可用字母m自行指定,如:
m!/u/jqpublic/perl/prog1!    等价于    /\/u\/jqpublic\/perl\/prog1/
而且换成其他字符后,/就不属于特殊字符了,不必加\/了


  pattern
\d或\d+      任意数字 [0-9]
\D或\D+     除数字外的任意字符  
/[\da-z]/   等同于/[0-9a-z]/
^    /^def/  只匹配以def打头的字符串
$    
/\\/         转义字符
/\*+/
             pattern中标点都要加\
[]           意味着匹配一组字符中的一个
* + ? .      通配符


   *+不能作为首字符,所以任意字符必须用显示表示法[0-9a-zA-Z]
$line=~
syntax error at ./address.pl line 6, near "out @int_hwaddress"
Quantifier follows nothing in regex; marked by <-- HERE in m at ./address.pl line 41
改为
$line=~/[0-9a-zA-Z]+:[0-9a-fA-F]+:[0-9a-fA-F]+:[0-9a-fA-F]+:[0-9a-fA-F]+:[0-9a-fA-F]+/
.

    pattern中空格就是" "
if(($input=~/^ping$/i)||($input=~/^ping $/i))
macg>ping
command:[ping xxx.xxx.xxx.xxx]
macg>ping                      带一个空格
command:[ping xxx.xxx.xxx.xxx]
IEI-nTracker>ping               带两个空格
Use of uninitialized value in concatenation (.) or string at /nettracker/ntshell/ntshell
 
if(($input=~/^ping$/i)||($input=~/^ping +$/i))
IEI-nTracker>ping     多个空格
command:[ping xxx.xxx.xxx.xxx]

if($_[0]=~/^ping +[0-9a-zA-Z\.]+$/i)
相当于"ping xxxxx"或"ping        xxxx"


    =~/want/是等于,还是含有???
当然是包含
等于其实就是exactly匹配,/^wang$/


    格式匹配(不是包含性符合),通常用于一些特殊格式输入时用(比如IP地址)
#!/usr/bin/perl

$file="/home/macg/perltest/gogo";
&gotest($file);

sub gotest{
my(@tmp)=@_;

open (MYFILE, $tmp[0]) || die ("Could not open file");
my($line,$newline);
while ($line=<MYFILE>) {
if ($line =~ /\d+\.\d+\.\d+\.\d+/) {
  print "$line";
  print "the ip add is good\n";
 } else {
  print "$line";
  print "the ip add is a error\n";
    }
  }
close(MYFILE);
}   
 
[macg@localhost perltest]$ cat gogo
202.106.0.20
10.0.0.as

[macg@localhost perltest]$ ./tip.pl
202.106.0.20
the ip add is good
10.0.0.as
the ip add is a error 
上面这个例子也不对,会出下面的错:包含以外的错误,所以应该加^ $
[macg@localhost perltest]$ cat gogo
202.106.0.20
10.0.0.as
10.0.0.1 as   
改成 if ($line =~ /^\d+\.\d+\.\d+\.\d+$/) {
[macg@localhost perltest]$ ./tip.pl
202.106.0.20
the ip add is good
10.0.0.as
the ip add is a error
10.0.0.1 as
the ip add is a error   


      /want/g与/want/的区别:指针后移,相当于find next
$line="inet addr:192.168.10.17  Bcast:192.168.10.255  Mask:255.255.255.0";
$line=~/(\d+)\.(\d+)\.(\d+)\.(\d+)/;
print "$&\n";       $&查询结果
$line=~/(\d+)\.(\d+)\.(\d+)\.(\d+)/;
print "$&\n";
$line=~/(\d+)\.(\d+)\.(\d+)\.(\d+)/;
print "$&\n";
[root@nm testpl]# ./tip.pl
192.168.10.17
192.168.10.17
192.168.10.17 
几次的查找都相同,因为每次都是回到“首部”找“一次”
找到一个,就返回值1,并停止比对
加g
$line="inet addr:192.168.10.17  Bcast:192.168.10.255  Mask:255.255.255.0";
$line=~/(\d+)\.(\d+)\.(\d+)\.(\d+)/g;
print "$&\n";
$line=~/(\d+)\.(\d+)\.(\d+)\.(\d+)/g;
print "$&\n";
$line=~/(\d+)\.(\d+)\.(\d+)\.(\d+)/g;
print "$&\n";
[root@nm testpl]# ./tip.pl
192.168.10.17
192.168.10.255
255.255.255.0  
加g后,好象文件指针一样,查一次,指针就移一格



   “或”下的比对,匹配的先后顺序很重要, 尤其是包含型的,要把精确的放前面
if (($ret=($line=~/eth[0-5]/))||($ret=($line=~/eth[0-5]:[0-5]/)))
 {
print "$&:";
$found=1;
 } elsif ($found)
  {
  print $line;
  $found=0;
  }
}
[mac@nm testpl]$ ./address.pl
eth0:          inet addr:10.4.3.117  Bcast:10.4.255.255  Mask:255.255.0.0
eth0:          inet addr:192.168.10.117  Bcast:192.168.10.255  Mask:255.255.255.0
eth0:          inet addr:192.168.1.142  Bcast:192.168.1.255  Mask:255.255.255.0
eth1:          BROADCAST MULTICAST  MTU:1500  Metric:1
改成精确的放前面
if (($ret=($line=~/eth[0-5]:[0-5]/))||($ret=($line=~/eth[0-5]/)))
[mac@nm testpl]$ ./address.pl
eth0:          inet addr:10.4.3.117  Bcast:10.4.255.255  Mask:255.255.0.0
eth0:1:          inet addr:192.168.10.117  Bcast:192.168.10.255  Mask:255.255.255.0
eth0:2:          inet addr:192.168.1.142  Bcast:192.168.1.255  Mask:255.255.255.0
eth1:          BROADCAST MULTICAST  MTU:1500  Metric:1 
先查到精确,就会跳过模糊的(部分的),否则会用模糊的(部分的)代替精确的


    $line =~ /want/ 完成,只返回1和null
比对不修改=~左边字符串
与比对截然不同,替换是修改=~左边字符串的
my($line,$newline);
while ($line=<MYFILE>) {
if($newline=($line=~/want/)) {
  print "found\n";
  print "\$line is:$line";
  print "\$newline is:$newline \n";
 } else {
  print "not found\n";
  print "\$line is:$line";
  print "\$newline is:$newline \n";
    }
  }
close(MYFILE);
}   
[macg@localhost perltest]$ ./tip.pl
not found
$line is:I glad to be Los angle
$newline is:
found
$line is:I want to be Los angle
$newline is:1 


    如何能找到比对结果?    用$&
while ($line=<MYFILE>) {
if ($line =~ /want/) {
  print "$line";
  print "\$\& is $&\n";
  print "good\n";
 } else {
  print "$line";
  print " error\n";
    }
  }   
[macg@localhost perltest]$ ./tip.pl
I want go to LA. and I also want to be NY.       $line没发生变化
$& is want                         $&是比对结果
good
But I glad to be D.C.
 error   

   注意if ($line=~/want/)和赋值毫无关系,所以不存在$line值改变的问题,$line只是操作符号=~左边的一个元素而已,所以也不存在返回值给$line的问题

    $&     $`      $' 的含义
while ($line=<MYFILE>) {
if ($line =~ /want/g) {
  print "good\n";
  print "$line";
  print  $& . "\n";
  print  $` . "\n";
  print  $' . "\n";
  print "good\n";
 } else {
  print " error\n";
  print "$line";
    }
  }  
[macg@localhost perltest]$ ./tip.pl
good
I want go to LA. and I also want to be NY.
want                  $&      $&是最后一个match,也可算是结果
I                      $`       match之前的所有字符
 go to LA. and I also want to be NY.    $'      match之后的所有字符

 

   !~ 比对不符合pattern      (其实没什么用,因为用if ( =~ ) else即可)


    perl可以将pattern再细分 ,再用$1,$2,$3,$4表示这些子match
步骤:
1.对想单独提出来的子pattern加( )
2.再用$1,$2来表示
if ($line =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
  print "good \n";
  print $line;
  print  $& . "\n";
  print $1,"\n";
  print $2,"\n";
  print $3,"\n";
  print $4,"\n";
[macg@localhost perltest]$ ./tip.pl
good
202.106.0.20
202.106.0.20
202
106
0
20  
 

   修饰词i          不计大小写
if ($line =~ /want/i) {
  print "good \n";
  print $line;
  print  $& . "\n"; 
[macg@localhost perltest]$ ./tip.pl
good
I WANT TO go to
WANT  

 
    修饰词x 在模式中忽略空格
/\d{2} ([\W]) \d{2} \1 \d{2}/x    等价于    /\d{2}([\W])\d{2}\1\d{2}/

 替换格式

命令与修饰词基本上与比对相同
格式: string command  s/pattern/欲置換的字串/修饰词
命令与比对相同
=~          先比对符合(=~)再替换
!~          比对不符合(!~)再替换


   基本替换(后面替换前面)
$line =~s/want/hate/i;
  print "good \n";
  print "\$line is :$line";
  print "\$\& is : $&", "\n";  
[macg@localhost perltest]$ ./tip.pl
good
$line is :I hate TO go to    与比对截然不同,替换是修改=~左边字符串的
$& is : WANT      替换里的$&和就是比对的$&
 

    修饰词i,不计大小写
$line =~s/want/hate/i;    將 $line中的 want 或 WANT,Want 換成 hate


    刪除(替换为空)
单纯的删除一般没用,实际应用中,基本上都用全域删除(g)

$line =~s/want//i;
  print "\$line is :$line";
[macg@localhost perltest]$ ./tip.pl
$line is :I  TO go to 
  
 
    g全域替换,替换所有的,缺省替换是查找到第一符合的就替换,然后停止
$line =~s/want/hate/ig;       修饰词可以连写
  print "good \n";
  print "\$line is :$line"
[macg@localhost perltest]$ cat gogo
I WANT TO go to NY. And I also want to be DC.
I glad to go to  

[macg@localhost perltest]$ ./tip.pl
$line is :I hate TO go to NY. And I also hate to be DC.



替换g与比对的g的不同
  • 比对g是find next,所以需要与while等合用
  • 替换不需要用循环语句,一句就能实现所有替换,即:替换不需要find and find next,替换可以find all in one time.


    e选项把替换部分的字符串看作表达式,在替换之前先计算其值
$string = "0abc1";
$string =~ s/[a-zA-Z]+/$& x 2/e;  将中间的字符(非数字)成倍
now $string = "0abcabc1"
$&是查找结果
    

    转换格式
string command tr/字元集/欲轉換的字元集/修饰词
string command y/字元集/欲轉換的字元集/修饰词
命令:=~  !~
修饰词:
d 刪除
s 將重覆刪除
c 非转换:將不在指定字元集中的字元(包括換行字元),換成欲轉換的字元集


   最基本的转换:字符串小写换大写
$line =~tr/a-z/A-Z/;
  print "\$line is :$line"; 
[macg@localhost perltest]$ cat gogo
I WANT TO go to NY. And I also want to be DC.
 
[macg@localhost perltest]$ ./tip.pl
good
$line is :I WANT TO GO TO NY. AND I ALSO WANT TO BE DC.   
转换和替换一样,也是修改string
 

    删除:     =~tr/要删除的字符//d

    全域替换删除和转换删除等价
全域替换删除    $line =~tr/\t//g;
转换删除        $line =~tr/\t//d;
  $line =~tr/\t//;            删除所有TAB  转化所有TAB为空//
  print "\$line is :$line";
[macg@localhost perltest]$ ./tip.pl
$line is :I WANT TO              go to NY. And   I also want to          be DC.            
发觉TAB没删掉,其实不是没删掉,只是只删了第一个TAB而已
  $line =~tr/\t//d;
  print "\$line is :$line";
[macg@localhost perltest]$ ./tip.pl
good
$line is :I WANT TO go to NY. And I also want to be DC. 


    删除重复字符:   =~ tr/a-zA-Z//s;      这功能没什么实际用途
$line=~ tr/a-zA-Z//s;
  print "\$line is :$line";  
[macg@localhost perltest]$ cat gogo
WANTWANT TO go to NNYY. And I also wWant to be DC.  
[macg@localhost perltest]$ ./tip.pl
good
$line is :I WANTWANT TO go to NY. And I also wWant to be DC.  


    tr转换不支持!~  只支持=~      因为修饰词c就相当于!~了
$text="1 abc 23 PID";
$text =~ tr/[0-9]c;      [0-90]c即非数字
 
 
一个CGI控件值的解码的示范程序:
$value="%A4T%A4K%21";
$value=~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
s替换%字符串,
并把符合的字符串传给$1
把$1通过e运算pack("C",hex($1))进行解码处理
pack("C",hex($1))把$1找到的十六进制数值转成十进制的码
C代表unsigned char value的意





posted on 2012-03-10 15:44 xzc 阅读(8211) 评论(0)  编辑  收藏 所属分类: linux/unix

只有注册用户登录后才能发表评论。


网站导航: