当前位置:早雪网网络学院编程文档Perl → perl常问问题集--第六篇

perl常问问题集--第六篇

减小字体 增大字体 作者:不详  来源:supcode.com收集整理  发布时间:2005-7-23 10:54:48

目录 
篇名 
概述 
我该如何使用正规表示式才不至於写出不合语法且难以维护的程式码? 
我无法对应到超过一行的内容,哪里出了问题? 
我如何取出位於不同行的两个模式间之内容? 
我把一个正规表示式放入 $/但却没有用。错在哪里? 
如何在 LHS端【译注:式子中运算元左端部份】作不区别大小写式的替换,但在 RHS端【右端】保留大小写区别? 
如何使 \w对应到附重音记号 (accented)的字元? 
如何作一个适合不同 locale【译注:国家、地区在文字编码上各自的惯例】的 /[a-zA-Z]/对应? 
在一个正规表示式里如何引入 (quote)变数? 
/o到底是干麽用的? 
如何使用正规表示式将档案中 C语言样式的注解删掉? 
我能用 Perl的正规表示式去对应成对的符号吗? 
有人说正规表示式很贪婪,那是什麽意思?该如何避免它所带来的问题? 
如何处理每一行的每个字? 
我如何印出文字出现频率或行出现频率的纲要? 
如何能作近似对应? 
我如何有效率地一次对应多个正规表示式? 
为何我用 \b作字界搜寻时会失败呢? 
为什麽每当我用 $&, $`,或 $'时程式的速度就慢下来了呢? 
正规表示式中的 \G能给我什麽好处? 
Perl正规表示引擎是 DFAs或 NFAs?它们是 POSIX相容的吗? 
在无递回的场合下用 grep或 map有什麽不对? 
如何对应多位元组字母所构成的字串? 
作者与版权事宜 

--------------------------------------------------------------------------------

篇名 
perlfaq6 -正规表示式??原文版 Revision: 1.17, Date: 1997/04/24 22:44:10 中译版 $Revision: 1.4 $, $Date: 1997/08/03 17:22:55 $) 


--------------------------------------------------------------------------------

概述 
本节之所以出人意料地小是因为在这份 FAQ 的其它部份已散布着与正规表示式有关的答案了。例如说,从一串文字中撷取 URL,以及检查字串是否含数字,这些都是以正 规表示式来处理的,但是这些问题的答案得到本 FAQ的其它部份去找 (更精确地说,是资料和网路那两部份)。 


--------------------------------------------------------------------------------

我该如何使用正规表示式才不至於写出不合语法且难以维护的程式码? 
以下提供叁个技巧使得你的正规表示式易懂又好维护。 

在正规表示式外围作注解。 
用 Perl的注解方式描述你所作的事以及你如何作到它。 
    #把每行变成「第一个字、冒号,和剩馀的字元数」这样的格式。
    s/^(\w+)(.*)/ lc($1) . ":" . length($2) /ge;

在正规表示式内部作注解。 
/x修饰子会要直译器忽略正规表示式内的任意空白 (在特定字元类别 [character class]中例外),同时也让你在式子中使用平常的注解方法。你应该能想像得到, 加上一些空白与注解帮助会有多大。 
/x让你把下面这行: 

    s{<(?:[^>'"]*|".*?"|'.*?')+>}{}gs;

变成: 

    s{ <                    #箭头括弧区起始
        (?:                 #划分「勿追溯前段」(non-backreferencing)的括弧
             [^>'"] *       #有零个以上、不是 >、 ',或 "的字元
                |           #或者是
             ".*?"          #一段双引号圈起来的区域 (吝啬式对应)
                |           #或者是
             '.*?'          #一段单引号圈起来的区域 (吝啬式对应)
        ) +                 #以上区域出现一次或多次
       >                    #箭头括弧区结束
    }{}gsx;                 #用空字串来替换;也就是杀掉

虽然它看来还是不够简明易懂,但至少大大有助於解释这个模式 (pattern)的意义。 

换个不同的区隔字元 (delimiter)。 
尽管我们平常都把正规表示式的模式 (patterns)想作是以 /字元来区隔,但实际上用几乎任何字元来作都行。perlre文件中有说明。例如,上面的 s///便是用大括号来当区隔字元的。选择另一个区隔字元可以免除在模式中得避开 (quote)区隔字元的困扰。例如: 
    s/\/usr\/local/\/usr\/share/g;      #选错区隔字元的後果【译注:
                                        #常被戏称为「搭牙签」症候群 ;-)】

    s#/usr/local#/usr/share#g;          #这样不是好多了?!


--------------------------------------------------------------------------------

我无法对应到超过一行的内容,哪里出了问题? 
若不是你的字串里少了换行字元,就是你在模式里用了错误的修饰子。 

有很多方法将多行的资料结合成一个字串。如果你希望在读入输入资料时自动得到 这项功能,你得重新设定 $/变数 (若为段落,设成 '';若要将整个档案读进一字 串,设成 undef ),以容许你一次能读入一行以上的输入。 

请参考 prelre,其中有选择 /s或 /m (或二者都用)的说明: /s让万用字元 (``.'')能对应到换行字元【译注:通常换行字元不在 ``.'' 的对应范围内】, /m则让 ``^''和 ``$''两个符号能够对应到任何换行字元的前後,而不只是像平常 那样只能对应到字串头尾。你所需要确定的是你的确有个多行的字串。 

例如说,以下这个程式会侦测出同一段落里重覆的字,即使它们之间有换行符号相隔 (但是不能隔段)。在这个例子里,我们不需要用到 /s,因为我们并未在任何要跨行对应的正规表示式中使用 ``.''。我们亦无需使用 /m,因为我们不想让 ``^''或 ``$''去对应 到字串中每个换行字元前後的位置。但重点是,我们得把 $/ 设成与内定值相异的值,否则我们实际上是无法读入一个多行的资料的。 

    $/ = '';            #读入一整段,而非仅是一行。
    while ( <> ) {
        while ( /\b(\w\S+)(\s+\1)+\b/gi ) {
            print "在段落 $.找到重复的字 $1\n";
        }
    }

以下的程式能找出开头为 ``From ''的句子 (许多邮件处理程式都会用到这个功能): 

    $/ = '';            #读入一整段,而非仅是一行。 
    while ( <> ) {
        while ( /^From /gm ) { # /m使得 ^也会对应到 \n之後
            print "开头为 From的段落 $.\n";
        }
    }

以下的程式会抓出在一个段落里所有夹在 START与 END之间的东西。 

    undef $/;           #把整个档案读进来,而非只是一行或一段
    while ( <> ) {
        while ( /START(.*?)END/sm ) { # /s使得 .能跨越行界
            print "$1\n";
        }
    }


--------------------------------------------------------------------------------

我如何取出位於不同行的两个模式间之内容? 
你可以使用看起来有点怪的 Perl ..运算元 (在 perlop文件中有说明): 

    perl -ne 'print if /START/ .. /END/' file1 file2 ...

如果你要的是整段文字而非各单行,你该使用: 

    perl -0777 -pe 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...

但是当 START和 END之间的东西作巢状(内含)式分布 (nested occurrences)的时候 ,你便得面对本篇中所提到的对称式文字对应的问题。 


--------------------------------------------------------------------------------

我把一个正规表示式放入 $/但却没有用。错在哪里? 
$/必须是个字串,不能是一个正规表示式。Perl得留一手,让 A

[1] [2] [3] [4]  下一页


Tags:perl,常问,问题,第六
[数据载入中...] [返回上一页] [打 印]