学习笔记 Perl grep函数使用揭秘

开发 架构
本文介绍一下Perl grep函数的概念,它会根据LIST中的元素对BLOCK或EXPR做出评估,而且会把局部变量$_设置为当前所用的LIST中的元素。

本文和大家重点讨论一下Perl grep函数的使用,Perl grep函数会根据LIST中的元素对BLOCK或EXPR做出评估,BLOCK块是一个或多个由花括号分隔开的Perl语句。而List则是一串被排序的值。

Perl grep函数的使用

关于Perl grep函数

(如果你是个Perl的新手,你可以先跳过下面的两段,直接到Grepvs.loops样例这一部分,放心,在后面你还会遇到它)

grepBLOCKLIST
grepEXPR,LIST

Perl grep函数会根据LIST中的元素对BLOCK或EXPR做出评估,而且会把局部变量$_设置为当前所用的LIST中的元素。BLOCK块是一个或多个由花括号分隔开的Perl语句。而List则是一串被排序的值。EXPR是一个或多个变量,操作符,字符,函数,子程序调用的综合体。Grep会返回一组经BLOCK或EXPR块的估值后是真的元素。如果BLOCK块由多个语句组成,那么Grep以BLOCK中的最后一条语句的估计值为准。LIST可以是一个列表也可以是一个数组。在标量上下文中,grep返回的是可以被BLOCK或EXPR估为真的元素个数。

请避免在BLOCK或EXPR块中修改$_,因为这会相应的修改LIST中的元素。同时还要避免把grep返回的列表做为左值使用,因为这也会修改LIST中的元素。(所谓左值变量就是一个在赋值表达式左边的变量)。一些Perlhackers可能会利用这个所谓的"特性",但是我建议你不要使用这种混乱的编程风格.

Perl grep函数与循环

这个例子打印出myfile这个文件中含有terriosm和nuclear的行(大小写不敏感).

  1. openFILE"<myfile"ordie"Can'topenmyfile:$!";  
  2. printgrep/terrorism|nuclear/i,<FILE>


对于文件很大的情况,这段代码耗费很多内存。因为grep把它的第二个参数作为一个列表上下文看待,所以<>操作符返回的是整个的文件。更有效的代码应该这样写:

 

  1. while($line=<FILE>){  
  2. if($line=~/terrorism|nuclear/i){print$line}  

通过上面可以看到,使用循环可以完成所有grep可以完成的工作。那为什么我们还要使用grep呢?一个直观的答案是grep的风格更像Perl,而loops(循环)则是C的风格。一个更好的答案是,首先,grep很直观的告诉读者正在进行的操作是从一串值中选出想要的。其次,grep比循环简洁。(用软件工程的说法就是grep比循环更具有内聚力)。基本上,如果你对Perl不是很熟悉,随便你使用循环。否则,你应该多使用像grep这样的强大工具.

计算数组中匹配给定模式的元素个数
在一个标量上下文中,grep返回的是匹配的元素个数.

$num_apple=grep/^apple$/i,@fruits;^和$匹配符的联合使用指定了只匹配那些以apple开头且同时以apple结尾的元素。这里grep匹配apple但是pineapple就不匹配。

输出列表中的不同元素

 

  1. @unique=grep{++$count{$_}<2}  
  2. qw(abacddefgfhh);  
  3. print"@unique\n"; 

输出结果:abcdefgh$count{$_}是Perl散列中的一个元素,是一个键值对(Perl中的散列和计算机科学中的哈希表有关系,但不完全相同)这里count散列的键就是输入列表中的各个值,而各键对应的值就是该键是否使BLOCK估值为真的次数。当一个值第一次出现的时候BLOCK的值被估为真(因为小于2),当该值再次出现的时候就会被估计为假(因为等于或大于2)。

取出列表中出现两次的值

  1. @crops=qw(wheatcornbarleyricecornsoybeanhay  
  2. alfalfaricehaybeetscornhay);  
  3. @duplicates=grep{$count{$_}==2}  
  4. grep{++$count{$_}>1}@crops;  
  5. print"@duplicates\n"; 

在grep的第一个列表元素被传给BLOCK或EXPR块前,第二个参数被当作列表上下文看待。这意味着,第二个grep将在左边的grep开始对BLOCK进行估值之前完全读入count散列。

列出当前目录中的文本文件

@files=grep{-fand-T}glob'*.*';
print"@files\n";
glob函数是独立于操作系统的,它像Unix的shell一样对文件的扩展名进行估计。单个的*表示匹配所以当前目录下不以.开头的文件,.*表示匹配当前目录下以.开头的所有文件.如果一个文件是文本文件-f和-T文件测试符则返回真。使用-fand-T进行测试要比单用-T进行测试有效,因为如果一个文件没有通过-f测试,那么-T测试就不会进行,而-f测试比-T耗时更少.

从数组中选出元素并消除重复

 

  1. @array=qw(Tobeornottobethatisthequestion);  
  2. print"@array\n";  
  3. @found_words=  
  4. grep{$_=~/b|o/iand++$counts{$_}<2;}@array;  
  5. print"@found_words\n"; 

输出结果:
Tobeornottobethatisthequestion
Tobeornottoquestio
逻辑表达式$_=~/b|o/i匹配包含有b或o的元素(区别大小写)。把匹配操作放在计数工作前要比把计数工作放在前面有效些。比如,如果左边的表达式测试失败,那么右边的表达式就不会被计算.

选出二维坐标数组中横坐标大于纵坐标的元素

 

  1. #Anarrayofreferencestoanonymousarrays  
  2. @data_points=([5,12],[20,-3],  
  3. [2,2],[13,20]);  
  4. @y_gt_x=grep{$_->[0]<$_->[1]}@data_points;  
  5. foreach$xy(@y_gt_x){print"$xy->[0],$xy->[1]\n"} 

输出结果:
5,12
13,20

在数据库中查找餐馆

这个例子实现数据库的方法不适合在实际中使用的,但是它说明了使用Perl grep函数的时候,只要你的内存够用,BLOCK块的复杂度基本没有限制.

 

  1. #@databaseisarrayofreferencestoanonymoushashes  
  2. @database=(  
  3. {name=>"WildGinger",  
  4. city=>"Seattle",  
  5. cuisine=>"AsianThaiChineseKoreanJapanese",  
  6. expense=>4,  
  7. music=>"\0",  
  8. meals=>"lunchdinner",  
  9. view=>"\0",  
  10. smoking=>"\0",  
  11. parking=>"validated",  
  12. rating=>4,  
  13. payment=>"MCVISAAMEX",  
  14. },  
  15. #{...},etc.  
  16. );  
  17.  
  18. subfindRestaurants{  
  19. my($database,$query)=@_;  
  20. returngrep{  
  21. $query->{city}?  
  22. lc($query->{city})eqlc($_->{city}):1  
  23. and$query->{cuisine}?  
  24. $_->{cuisine}=~/$query->{cuisine}/i:1  
  25. and$query->{min_expense}?  
  26. $_->{expense}>=$query->{min_expense}:1  
  27. and$query->{max_expense}?  
  28. $_->{expense}<=$query->{max_expense}:1  
  29. and$query->{music}?$_->{music}:1  
  30. and$query->{music_type}?  
  31. $_->{music}=~/$query->{music_type}/i:1  
  32. and$query->{meals}?  
  33. $_->{meals}=~/$query->{meals}/i:1  
  34. and$query->{view}?$_->{view}:1  
  35. and$query->{smoking}?$_->{smoking}:1  
  36. and$query->{parking}?$_->{parking}:1  
  37. and$query->{min_rating}?  
  38. $_->{rating}>=$query->{min_rating}:1  
  39. and$query->{max_rating}?  
  40. $_->{rating}<=$query->{max_rating}:1  
  41. and$query->{payment}?  
  42. $_->{payment}=~/$query->{payment}/i:1  
  43. }@$database;  
  44. }  
  45.  
  46. %query=(city=>'Seattle',cuisine=>'Asian|Thai');  
  47. @restaurants=findRestaurants(\@database,\%query);  
  48. print"$restaurants[0]->{name}\n";  
  49.  

 

输出结果:WildGinger

【编辑推荐】

  1. Eclipse平台中Perl脚本开发
  2. Perl学习笔记----Perl命令行
  3. Perl数组和引用使用指导
  4. Perl基础 解析Perl标量和数组概念
  5. Perl模式匹配中的特殊字符用法指南


 

责任编辑:佚名 来源: csdn.net
相关推荐

2010-07-21 14:18:27

Perl函数

2010-07-23 13:53:33

Perl grep函数

2010-07-19 15:31:10

Perl关联数组函数

2010-07-26 10:09:01

Perl split函

2010-07-21 13:27:06

Perl模式匹配

2010-07-21 14:08:28

Perl命令行

2010-07-13 12:50:47

Perl变量

2010-07-15 18:04:20

Perl模式

2010-07-16 12:50:45

Perl语言

2010-07-26 10:51:26

Perl模式匹配

2010-07-20 15:18:41

Perl基本语法

2010-07-13 13:15:17

Perl

2010-07-16 17:38:12

Perl包

2010-07-15 10:07:29

Perl指令

2010-07-13 15:43:57

Perl语言

2010-07-19 09:08:38

Perl模块

2010-07-15 11:29:25

Perl格式化输出

2010-07-15 14:54:50

Perl线程

2010-07-21 10:18:41

Perl map函数

2010-07-20 10:58:39

Perl脚本
点赞
收藏

51CTO技术栈公众号