学习笔记 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的行(大小写不敏感).

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


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

 

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

  • 1.
  • 2.
  • 3.

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

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

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

输出列表中的不同元素

 

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

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

取出列表中出现两次的值

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

在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耗时更少.

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

 

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

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

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

 

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

输出结果:
5,12
13,20

在数据库中查找餐馆

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

 

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

Perl变量

2010-07-21 14:08:28

Perl命令行

2010-07-13 13:15:17

Perl

2010-07-16 17:38:12

Perl包

2010-07-26 10:51:26

Perl模式匹配

2010-07-20 15:18:41

Perl基本语法

2010-07-16 12:50:45

Perl语言

2010-07-15 18:04:20

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-20 10:58:39

Perl脚本

2010-07-19 11:07:13

Perl控制结构
点赞
收藏

51CTO技术栈公众号