Perl食谱1
取自 PerlChina.org - wiki
Perl食谱1
- 原 名:Cooking with Perl
- 中 文: Perl 食谱 - 1
- 作 者:Tom Christiansen,Nathan Torkington
- 原 文:http://www.perl.com/pub/a/2003/08/21/perlcookbook.html
- 发 表:2003 年 8 月 21 日
- 翻 译:saladjonk
- 审 校:qiang chunzi
- 出 处:中国 Perl协会 FPC - PerlChina.org
目录 |
编者的话:最新版的 Perl Cookbook 马上就要放上书店的书架开始发售了,这里我们介绍一些第二版里新增的内容,你可以先看看这些节选的内容。这周我们要介绍的是从第六章“模式匹配”和第八章“文件操作”中节选的内容。一定记住下周还来这个地方哦,我们会介绍脱离数据库来使用 SQL 语言,从表格中提取数据,用 HTML::Mason 的模板技术进行网页模板编程等。
[编辑] 技巧摘录:匹配多重嵌套的模式
[编辑] 提出问题
你想匹配由多重定界符构成的嵌套模式,比如一个函数的参数。
[编辑] 解决方案
层层匹配,每层匹配后把该层的模式替换为匹配的值
my $np;
$np = qr{
\(
(?:
(?> [^( )]+ ) # Non-capture group w/o backtracking
|
(??{ $np }) # Group with matching parens
)*
\)
}x;
或者直接使用 Text::Balanced 模块的 extract_bracketed 函数。
[编辑] 讨论
$(??{_CODE_}) 结构将运行 CODE 所代表的代码,然后用得到的结果来替换模式,一个简单的,不带递归的的匹配回文结构的例子如下:(注:回文结构就是一个词的构成具有前后对称性,如“deed”,“peoep”)
if ($word =~ /^(\w+)\w?(??{reverse $1})$/ ) {
print "$word is a palindrome.\n";
}
考虑 “reviver” 这个单词,他将会作为回文被匹配。$1 内置变量在匹配中保存 “rev”。后面跟任意“一个”字符 ,此时为”。然后 reverse $1 语句产生“ver”字符串,并且插入 reverse $1 语句所在位置来进行匹配。
要匹配一些均衡的模式,你需要用到递归,递归方法有一些技巧性。一个包含 (??{CODE}) 的复合模式可以引用它自己。在“解决方法”部分中给出的模式匹配一系列嵌套的参数,不论嵌套多深都可以匹配。使用上面已经定义的 $np , 你就可以用它来匹配一个函数的参数。
$text = "myfunfun(1,(2*(3+4)),5)"; $funpat = qr/\w+$np/; # $np as above $text =~ /^$funpat$/; # Matches!
在 CPAN 上有很多处理匹配(或解析)多层嵌套字符串的模块。Regexp::Common 模块提供很多封装好的模式来匹配那些怪异的字符串。例如:
use Regexp::Common;
$text = "myfunfun(1,(2*(3+4)),5)";
if ($text =~ /(\w+\s*$RE{balanced}{-parens=>'( )'})/o) {
print "Got function call: $1\n";
}
Regexp::Common 提供的其它模模式匹配各种不同标记法中的数字和引起来的字符串:
$RE{num}{int}
$RE{num}{real}
$RE{num}{real}{'-base=2'}{'-sep=,'}{'-group=3'}
$RE{quoted}
$RE{delimited}{-delim=>'/'}
标准的 Text::Balanced 模块在(5.8版)则提供一个统一方法匹配那些数字和字符串:
use Text::Balanced qw/extract_bracketed/;
$text = "myfunfun(1,(2*(3+4)),5)";
if (($before, $found, $after) = extract_bracketed($text, "(")) {
print "answer is $found\n";
} else {
print "FAILED\n";
}
[编辑] 建议阅读
“Programming Perl 3rd Edition”一书第5章中的“Pattern Matching”一节;CPAN 上 Regexp::Common 模块和标准 Text::Balanced 模块的相关文档
摘录人:Tome Christiansen,Nathan Torkington
[编辑] 技巧节选:把字符串当作文件
[编辑] 提出问题
现在你手头上有的是字符串,但是你想把它作为一个文件来处理。例如,有一个子函数,它的参数为文件句柄,但是你想这个函数直接作用于你的字符串,而你不想把字符串写入一个文件。
[编辑] 解决方案
用 Perl 5.8 版中的 I/O 标量:
open($fh,"+<",\$string); # 从 $string 中读取数据
[编辑] 讨论
Perl 的输入输出层支持把数据存入标量及从标量中取出数据。像上面,当你用 <$fh> 语句读取一条记录的时候,你读的是 $string 中所存储数据的下一行。当你用 print 函数向 $string 中写入数据时,你会改变 $string 中现有的数据。你可以把 $fh 传递给一个参数为文件句柄的函数,而那个函数将不会知道它实际在处理字符串而不是文件。
Perl 也能以各种不同的方式来打开字符串,所以,你可以用只读、覆盖、追加等方式打开:
open($fh, "<", \$string); # 只读方式打开字符串 open($fh, ">", \$string); # 先清空字符串,然后字符串只写 open($fh, "+>", \$string); # 先清空字符串,字符串可读可写 open($fh, "+<", \$string); # 字符串可读可写,但是写的时候添加在已有内容的后面
这些返回的句柄完全和文件句柄一样,所以所有针对文件的 I/O 操作都能继续用,例如 seek,truncate,sysread 和 friends。
[编辑] 建议阅读
“Programming Perl,3rd Edition”一书第29章 perlfunc(1) 中的对 open 函数的介绍;“Using Random-Access I/O” 和“Setting the Default I/O Layers” 这两篇文章。
