本文和大家重点学习一下Perl grep函数的用法,Perl grep函数有两种表达方式,具体是哪两种请看本文的详细介绍吧。
Perl grep函数详解
(一)grep有2种表达方式:
◆grepBLOCKLIST
◆grepEXPR,LIST
BLOCK表示一个code块,通常用{}表示;EXPR表示一个表达式,通常是正则表达式。原文说EXPR可是任何东西,包括一个或多个变量,操作符,文字,函数,或子函数调用。
LIST是要匹配的列表。
Perl grep函数对列表里的每个元素进行BLOCK或EXPR匹配,它遍历列表,并临时设置元素为$_。在列表上下文里,grep返回匹配命中的所有元素,结果也是个列表。在标量上下文里,grep返回匹配命中的元素个数。
(二)grepvs.loops
openFILE"printgrep/terrorism|nuclear/i,;;
这里打开一个文件myfile,然后查找包含terrorism或nuclear的行。;返回一个列表,它包含了文件的完整内容。可能你已发现,如果文件很大的话,这种方式很耗费内存,因为文件的所有内容都拷贝到内存里了。
代替的方式是使用loop(循环)来完成:
- while($line=;){
- if($line=~/terrorism|nuclear/i){print$line}
- }
上述code显示,loop可以完成grep能做的任何事情。那为什么还要用grep呢?答案是grep更具Perl风格,而loop是C风格的。
更好的解释是:(1)grep让读者更显然的知道,你在从列表里选择某元素;(2)grep比loop简洁。
一点建议:如果你是Perl新手,那就规矩的使用loop比较好;等你熟悉Perl了,就可使用grep这个有力的工具。
(三)几个Perl grep函数的示例
1.统计匹配表达式的列表元素个数
$num_apple=grep/^apple$/i,@fruits;
在标量上下文里,grep返回匹配中的元素个数;在列表上下文里,grep返回匹配中的元素的一个列表。
所以,上述code返回apple单词在@fruits数组中存在的个数。因为$num_apple是个标量,它强迫grep结果位于标量上下文里。
2.从列表里抽取***元素
- @unique=grep{++$count{$_}<2}
- qw(abacddefgfhh);
- print"@uniquen";
上述code运行后会返回:abcdefgh
即qw(abacddefgfhh)这个列表里的***元素被返回了。为什么会这样呀?让我们看看:
%count是个hash结构,它的key是遍历qw()列表时,逐个抽取的列表元素。++$count{$_}表示$_对应的hash值自增。在这个比较上下文里,++$count{$_}与$count{$_}++的意义是不一样的哦,前者表示在比较之前,就将自身值自增1;后者表示在比较之后,才将自身值自增1。所以,++$count{$_}<2表示将$count{$_}加1,然后与2进行比较。$count{$_}值默认是undef或0。所以当某个元素a***次被当作hash的关键字时,它自增后对应的hash值就是1,当它第二次当作hash关键字时,对应的hash值就变成2了。变成2后,就不满足比较条件了,所以a不会第2次出现。
所以上述code就能从列表里***1次的抽取元素了。
◆抽取列表里精确出现2次的元素
- @crops=qw(wheatcornbarleyricecornsoybeanhay
- alfalfaricehaybeetscornhay);
- @duplicates=grep{$count{$_}==2}
- grep{++$count{$_}>;1}@crops;
- print"@duplicatesn";
运行结果是:rice
这里grep了2次哦,顺序是从右至左。首先grep{++$count{$_}>;1}@crops;返回一个列表,列表的结果是@crops里出现次数大于1的元素。
然后再对产生的临时列表进行grep{$count{$_}==2}计算,这里的意思你也该明白了,就是临时列表里,元素出现次数等于2的被返回。
所以上述code就返回rice了,rice出现次数大于1,并且精确等于2,明白了吧?:-)
3.在当前目录里列出文本文件
- @files=grep{-fand-T}glob'*.*';
- print"@filesn";
这个就很容易理解哦。glob返回一个列表,它的内容是当前目录里的任何文件,除了以'.'开头的。{}是个code块,它包含了匹配它后面的列表的条件。这只是grep的另一种用法,其实与grepEXPR,LIST这种用法差不多了。-fand-T匹配列表里的元素,首先它必须是个普通文件,接着它必须是个文本文件。据说这样写效率高点哦,因为-T开销更大,所以在判断-T前,先判断-f了。
4.选择数组元素并消除重复
- @array=qw(Tobeornottobethatisthequestion);
- @found_words=
- grep{$_=~/b|o/iand++$counts{$_}<2;}@array;
- print"@found_wordsn";
运行结果是:Tobeornottoquestion
{}里的意思就是,对@array里的每个元素,先匹配它是否包含b或o字符(不分大小写),然后每个元素出现的次数,必须小于2(也就是1次啦)。
grep返回一个列表,包含了@array里满足上述2个条件的元素。
5.从二维数组里选择元素,并且x
- #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"}
运行结果是:
5,12
13,20
这里,你应该理解匿名数组哦,[]是个匿名数组,它实际上是个数组的引用(类似于C里面的指针)。
@data_points的元素就是匿名数组。例如:
foreach(@data_points){
print$_->;[0];}
这样访问到匿名数组里的第1个元素,把0替换成1就是第2个元素了。
所以{$_->;[0]<$_->;[1]}就很明白了哦,它表示每个匿名数组的***个元素的值,小于第二个元素的值。而grep{$_->;[0]<$_->;[1]}@data_points;就会返回满足上述条件的匿名数组列表。所以,就得到你要的结果啦!
6.简单数据库查询
Perl grep函数的{}复杂程度如何,取决于program可用虚拟内存的数量。如下是个复杂的{}示例,它模拟了一个数据库查询:
- #@databaseisarrayofreferencestoanonymoushashes
- @database=(
- {name=>;"WildGinger",
- city=>;"Seattle",
- cuisine=>;"AsianThaiChineseKoreanJapanese",
- expense=>;4,
- music=>;"",
- meals=>;"lunchdinner",
- view=>;"",
- smoking=>;"",
- 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";
运行结果是:WildGinger
【编辑推荐】