HomeFeedRegex BBS

我爱正则表达式

关注正则表达式和搜索引擎

[转]正则表达式高级技巧基本概念实例详解[译]2009-06-02 9:03 am

admin

rex按:本文转自笨人干笨活的文章:正则表达式高级技巧基本概念实例详解[译],其RSS在这里:http://blog.benhuoer.com/subscribe/

英文原文来自Smashing Magazine。由笨活儿翻译。转载请注明出处。

正则表达式(Regular Expression, abbr. regex) 功能强大,能够用于在一大串字符里找到所需信息。它利用约定俗成的字符结构表达式来发生作用。不幸的是,简单的正则表达式对于一些高级运用,功能远远不够。若要进行筛选的结构比较复杂,你可能就需要用到高级正则表达式

本文为您介绍正则表达式的高级技巧。我们筛选出了八个常用的概念,并配上实例解析,每个例子都是满足某种复杂要求的简单写法。如果你对正则的基本概念尚缺乏了解,请先阅读这篇文章,或者这个教程,或者维基条目

这里的正则语法适用于PHP,与Perl兼容。

1. 贪婪/懒惰

Greed

所有能多次限定的正则运算符都是贪婪的。他们尽可能多地匹配目标字符串,也就是说匹配结果会尽可能地长。不幸的是,这种做法并不总是我们想要的。因此,我们添加“懒惰”限定符来解决问题。在各个贪婪运算符后添加“?”能让表达式只匹配尽可能短的长度。另外,修改器“U”也能惰化能多次限定的运算符。理解贪婪与懒惰的区别是运用高级正则表达式的基础。

贪婪操作符

操作符 * 匹配之前的表达式零次或零次以上。它是一个贪婪操作符。请看下面的例子:

preg_match( '/<h1>.*<\/h1>/', '<h1>这是一个标题。</h1>
<h1>这是另一个。</h1>', $matches ); 

句点(.)能代表除换行符外的任意字符。上面的正则表达式匹配 h1 标签以及标签内的所有内容。它用句点(.)和星号(*)来匹配标签内的所有内容。匹配结果如下:

<h1>这是一个标题。</h1><h1>这是另一个。</h1>

整个字串都被返回。* 操作符会连续匹配所有内容—— 甚至包括中间的 h1 闭合标签。因为它是贪婪的,匹配整个字串是符合其利益最大化原则。

懒惰操作符

把上面的式子稍作修改,加上一个问号(?),能让表达式变懒惰:

/<h1>.*?<\/h1>/

这样它会觉得,只需匹配到第一个 h1 结尾标签就完成任务了。

另一个有着类似属性的贪婪操作符是 {n,} 。它代表之前的匹配模式重复n次或n次以上,如果没有加上问号,它会寻找尽可能多的重复次数,加上的话,则会尽可能少重复(当然也就是“重复n次”最少)。

# 建立字串
$str = 'hihihi oops hi';
# 使用贪婪的{n,}操作符进行匹配
preg_match( '/(hi){2,}/', $str, $matches );  # matches[0] 将是 'hihihi'
# 使用堕化了的 {n,}? 操作符匹配
preg_match( '/(hi){2,}?/', $str, $matches );  # matches[0] 将是 'hihi'

2. 回返引用(Back referencing)

Back Referencing

有什么用?

回返引用(Back referencing)一般被翻译成“反向引用”、“后向引用”、“向后引用”,个人觉得“回返引用”更为贴切[笨活儿]。它是在正则表达式内部引用之前捕获到的内容的方法。例如,下面这个简单例子的目的是匹配出引号内部的内容:

# 建立匹配数组
$matches = array();

# 建立字串
$str = ""This is a 'string'"";

# 用正则表达式捕捉内容
preg_match( "/(\"|').*?(\"|')/", $str, $matches );

# 输出整个匹配字串
echo  $matches[0];

它会输出:

"This is a'

显然,这并不是我们想要的内容。

这个表达式从开头的双引号开始匹配,遭遇单引号之后就错误地结束了匹配。这是因为表达式里说:("|'),也就是双引号(")和单引号(')均可。要修正这个问题,你可以用到回返引用。表达式\1,\2,…,\9 是对前面已捕获到的各个子内容的编组序号,能作为对这些编组的“指针”而被引用。在此例中,第一个被匹配的引号就由\1代表。

如何运用?

将上面的例子中,后面的闭合引号替换为1:

preg_match( '/(\"|').*?\1/', $str, $matches );

这会正确地返回字串:

"This is a 'string'"

译注思考题:

如果是中文引号,前引号和后引号不是同一个字符,怎么办?

还记得PHP函数 preg_replace 吗?其中也有回返引用。只不过我们没有用 \1 … \9,而是用了 $1 … $9 … $n (此处任意数目均可)作为回返指针。例如,如果你想把所有的段落标签<p>都替换成文本:

$text = preg_replace( '/<p>(.*?)</p>/',
"&lt;p&gt;$1&lt;/p&gt;", $html );

参数$1是一个回返引用,代表段落标签<p>内部的文字,并插入到替换后的文本里。这种简便易用的表达式写法为我们提供了一个获取已匹配文字的简单方法,甚至在替换文本时也能使用。

3. 已命名捕获组(Named Groups)

当在一个表达式内多次用到回调引用时,很容易就把事情搞混淆,要弄清那些数字(1 … 9)都代表哪一个子内容是件很麻烦的事。回调引用的一个替代方法是使用带名字的捕获组(下文简称“有名组”)。有名组使用(?P<name>pattern)来设定,name代表组名,pattern是配合该有名组的正则结构。请看下面的例子:

/(?P<quote>"|').*?(?P=quote)/

上式中,quote就是组名,"|'是改组匹配内容的正则。后面的(?P=quote)是在调用组名为quote的有名组。这个式子的效果和上面的回调引用实例一样,只不过是用了有名组来实现。是不是更加易读易懂了?

有名组也能用于处理已匹配内容之数组的内部数据。赋予特定正则的组名也能作为所匹配到的内容在数组内部的索引词。

preg_match( '/(?P<quote>"|\')/', "'String'", $matches );

# 下面的语句输出“'”(不包括双引号)
echo $matches[1];

# 使用组名调用,也会输出“'”
echo $matches['quote'];

所以,有名组并不只是让写代码更容易,它也能用于组织代码。

4. 字词边界(Word Boundaries)

Word Boundaries

字词边界是字串里的字词字符(包括字母、数字和下划线,自然也包括汉字)和非字词字符之间的位置。其特殊之处就在于,它并不匹配某个实在的字符。它的长度是\b 匹配所有字词边界。

不幸的是,字词边界一般都被忽视掉了,大部分人都没有在意他的现实意义。 例如,如果你想要匹配单词“import”:

/import/

注意了!正则表达式有时候很调皮的。下面的字串也能和上面的式子匹配成功:

important

你或许觉得,只要在import前后加上空格,不就可以匹配这个独立的单词了:

/ import /

那如果遇上这种情况呢:

The trader voted for the import

当 import 这个词在字串开头或者结尾时,修改后的表达式仍然不能用。因此,考虑各种情况是必须的:

/(^import | import | import$)/i

别慌,还没完呢。如果遇到标点符号了呢?就为了满足这一个单词的匹配,你的正则可能就需要这样写:

/(^import(:|;|,)? | import(:|;|,)? | import(\.|\?|\!)?$)/i

对于只匹配一个单词来说,这样做实在是有点大动干戈了。正因如此,字词边界才显得意义重大。要适应上述要求,以及很多其他情况变种,有了字符边界,我们所需写的代码只是:

/\bimport\b/

上面所有情况都得到了解决。 \b 的灵活性就在于,它是一个没有长度的匹配。它只匹配两个实际字符之间想象出的位置。它检查两个相邻字符是否是一个为单字,另一个为非单字。情况符合,就返回匹配。如果遇到了单词的开头或结尾, \b 会把它当成是非单词字符对待。由于import里面的 i 仍然被看成是单词字符,import 就被匹配出来了。

注意,与\b相对,我们还有\B,此操作符匹配两个单字或者两个非单字之间的位置。因此,如果你想匹配在某个单词内部的‘hi’,可以使用:

\Bhi\B

“this”、“hight”,都会返回匹配,而“hi there”则不会返回匹配。

5. 最小组团(Atomic Groups)

Advanced Operators

最小组团是无捕捉的特殊正则表达式分组。通常用来提高正则表达式的效能,也能用于消除特定匹配。一个最小组团可以用(?>pattern) 来定义,其中pattern是匹配式。

/(?>his|this)/

当正则引擎针对最小组团进行匹配时,它会跳过组团内标记的回溯位置。以单词“smashing”为例,当用上面的正则表达式匹配时,正则引擎会先尝试在“smashing”里寻找“his”。显然,找不到任何匹配。此时,最小组团就发挥作用了:正则引擎会放弃所有回溯位置。也就是说,它不会尝试再从“smashing”里查找“this”。为什么要这样设置?因为“his”都没有返回匹配结果,包含有“his”的“this”当然就更匹配不了了!

上面的例子并没有什么实用性,我们用/t?his?/ 也能达到效果。再看看下面的例子:

/\b(engineer|engrave|end)\b/

如果把“engineering”拿去匹配,正则引擎会先匹配到“engineer”,但接下来就遇到了字词边界,\b,所以匹配不成功。然后,正则引擎又会尝试在字串里寻找下一个匹配内容:engrave。匹配到eng的时候,后面的又对不上了,匹配失败。最后,尝试“end”,结果同样是失败。仔细观察,你会发现,一旦engineer匹配失败,并且都抵达了字词边界,“engrave”和“end”这两个词就已经不可能匹配成功了。这两个词都比engineer短小,正则引擎不应该再多做无谓的尝试。

/\b(?>engineer|engrave|end)\b/

上面的替代写法更能节省正则引擎的匹配时间,提高代码的工作效率。

6. 递归(Recursion)

Recursion

递归(Recursion)用于匹配嵌套结构,例如括弧嵌套, (this (that)),HTML标签嵌套<div><div></div></div>。我们使用(?R)来代表递归过程中的子模式。下面是一个匹配嵌套括弧的例子:

/\(((?>[^()]+)|(?R))*\)/

最外层使用了反义符的括号“\(”匹配嵌套结构的开端。然后是一个多选项操作符( * | * ),可能匹配除括号外的所有字符 “(?>[^()]+)”,也可能是通过子模式“(?R)”来再次匹配整个表达式。请注意,这个操作符会尽量多地匹配所有嵌套。

递归的另一个实例如下:

/<([\w]+).*?>((?>[^<>]+)|((?R)))*<\/\1>/

以上表达式综合运用了字符分组,贪婪操作符、回溯,以及最小化组团来匹配嵌套标签。第一个括弧内分组([w]+)匹配出标签名,用于接下来的应用。若找到这尖括号样式的标签,则尝试寻找标签内容的剩余部分。下一个括弧括起来的子表达式和上一个实例非常相似:要么匹配不包括尖括号的所有字符 ?>[^<>]+,要么递归匹配整个表达式(?R)。表达式最后的</1>代表闭合标签。

7. 回调(Callbacks)

Callbacks

匹配结果中的特定内容有时可能会需要某种特别的修改。要应用多重而复杂的修改,正则表达式的回调就有了用武之地。回调是用于函数preg_replace_callback中的动态修改字串的方式。你可以为preg_replace_callback指定某个函数为参数,此函数能接收匹配结果数组为参数,并将数组修改后返回,作为替换的结果。

例如,我们想将某字串中的字母全部转变成大写。十分不巧,PHP没有直接转化字母大小写的正则操作符。要完成这项任务,就可以用到正则回调。首先,表达式要匹配出所有需要被大写的字母:

/\b\w/

上式同时使用了字词边界和字符类。光有这个式子还不够,我们还需要一个回调函数:

function upper_case( $matches ) {
return strtoupper( $matches[0] );
}

函数upper_case接收匹配结果数组,并将整个匹配结果转化成大写。 在此例中,$matches[0]代表需要被大写化的字母。然后,我们再利用preg_replace_callback实现回调:

preg_replace_callback( '/\b\w/', "upper_case", $str );

一个简单的回调即有这般强大的力量。

8. 注释(Commenting)

Commenting

注释不用来匹配字串,但确实是正则表达式中最重要的部分。当正则越写越深入,越写越复杂,要推译出究竟什么东西被匹配就会变得越来越困难。在正则表达式中间加上注释,是最小化将来的迷糊和困惑的最佳方式。

要在正则表达式内部加上注释,使用(?#comment)格式。把“comment”替换成你的注释语句:

/(?#数字)\d/

如果你打算把代码公之于众,为正则表达式加上注释就显得尤为重要。这样别人才能更容易看懂和修改你的代码。和其他场合的注释一样,这样做也能为你重访自己以前写的程序时提供方便。

考虑使用“x”或“(?x)”修改器来格式化注释。这个修改器让正则引擎忽略表达式参数之间的空格。“有用的”空格仍然能够通过[ ]\ (反义符加空格)来匹配。

/
\d    #digit
[ ]   #space
\w+   #word
/

上面的代码与下面的式子作用一样:

/\d(?#digit)[ ](?#space)\w+(?#word)/

请时刻注意代码的可读性。

更多资源(英文)

关于作者

Karthik Viswanathan 是一个喜欢编程和做网站的高中生。你可以到他的博客上查看他的作品:Lateral Code。你也可以关注一下他的线上Twitter应用

Permanent Link | Posted in 翻译 | Tags on: , , , , , ,

正则杂谈:从“评论已关闭”到正则表达式之眼2009-05-27 10:07 am

admin

近来沸沸扬扬地一条饭否消息是评论已关闭,这个关键词真的选的很好,它一下子把所有的一类敏感问题都串起来了,找到了该类问题的共同特征。至于为什么关闭评论,关闭的标准是什么,这里都不做探讨,只是从正则角度谈论一下技术而已。

所谓正则表达式,其实是一种抽象,是从现有的文本中找到规律,然后用正则的语言描述出来。例如,上次有人问,以http开头的,以空格结尾的正则式如何写?这个问题不难,我们只要符合这两个要求即可,即^(http\S+)\s。至于http后面的冒号、双斜杠,都不必劳神去匹配。这样写出来的正则表达式简洁明快,清晰易读。当然,从效率出发,越精确的正则式越有利于尽早失败,有利于提升效率。权衡写的效率与执行的效率,其过程也是很不错的。

Permanent Link | Posted in 杂项 | Tags on:

EmEditor中的正则表达式2009-04-25 9:32 pm

admin

Rex按:原本在翻译EmEditor自带的帮助文件中关于正则表达式的部分,翻译至一半,忽然想搜索一下是否有人已经翻译。结果发现,果然已经有人早已做好。我就不再重复劳动了。

文章来源:【正则表达式专题】正则表达式介绍及其在EmEditor的应用(更新)
作者:nb590

应lyh728之约, 也算是对命令行和正则表达式专题的支持, 随便写点东西介绍下正则表达式的基础概念. 由于本版偏重应用, 故只取EmEditor的正则子集来作介绍. Perl 和 CLR 的 Regex 的内容远比这类编辑器所支持的功能多.

正则表达式实在包含的内容太多, 仅仅用一篇文章来涵盖是没可能的了, 所以我只是简要的做些介绍和基本的模式应用举例. 即使这样也需要多次分章节的来连载了~~~ 闲话少说, 以下正文:

正则表达式, 英文 Regular expression, 简写Regexes或Regex.

应用概述: 提供与预期的搜索结果匹配的确切文本来进行字符串的搜索和替换操作, 这种技术不仅仅用于开发领域, 更被集成到一些常见的文本扩展编辑器, 如UltraEdit, Emeditor等. 历史上第一个实用应用程序是Unix 中的qed 编辑器。

举一个简单的类比: 我们对DOS中的通配符”*”和”?”应该很熟悉, 如命令”dir *.exe” 将列出所有后缀名为exe的文件名. 正则表达式提供的方法与其类似, 而且远比通配符强大的多.

从某种意义上说, 正则表达式是一种语言, 通过及其简短的一行代码即可以高效, 精确的描述要匹配的复杂文本, 当然, 它最大的优点也是他最大的缺点: 语法复杂, 创建困难. (熟悉之后就可以忽略后半句了 )

主要应用:

  • 数据验证; 这是正则表达式在开发中最常见的应用, 通过测试字符串内的模式。来验证输入的字符串是否为邮政编码, 电话号码, 电子邮件地址, 信用卡号码等等。
  • 搜索和替换文本; 用正则表达式来搜索文档中的特定文本块, 根据需要用其他指定的文本块进行替换。这也是文本编辑中的一个常见应用, 如将网页中的HTML代码转化为UBB代码.

既然发在『软件使用』板, 正则表达式的开发中的应用就不介绍了, 以下仅以EmEditor中的正则表达式来作介绍:

1. 启用正则表达式

菜单: Search – Find (Replace) – 选中 Use Regular Expressions

2. Emeditor 正则语法

正则表达式是普通字符和元字符组合的一种模式. 它的结构与算术表达式的结构类似, 各种元字符和运算符可以将小的表达式组合起来,创建大的表达式。通过在一对分隔符之间放置表达式模式的各种组件,就可以构建正则表达式。

2.1 普通字符

普通字符是指除了 “.”, “*”, “?”, “+”, “(”, “)”, “{”, “}”, “[", "]“, “^”, “$” 和 “\” 这些特殊字符之外的所有其他字符. 而这些特殊字符也可以通过前面加上”\”前缀而变为普通字符. 比如, 搜索”CCF”即为在文本中匹配所有的”CCF”字符串, 搜索”\[CCF\]“则是在文本中匹配所有的”[CCF]“字符串.

简而言之, 普通字符即为只匹配自身的字符.

2.2 元字符

元字符不匹配其自身,它用特殊方式来解析从而实现更多的逻辑功能。正则表达式通过元字符在模式中包含选择和循环

2.2.1 特殊字符

  • . 匹配除换行符 \n 之外的任何单个字符。
  • ( ) 分组捕获(子表达式)的开始和结束。可以捕获子表达式以供以后使用。
  • [ ] 中括号表达式的开始。
    中括号表达式是在方括号内包含一个或多个字符构成的列表的表达式。普通字符在中括号内表示本身,大多数特殊字符在中括号表达式内出现时失去它们的意义。除了转义字符’\', (要包含’\', 需要使用’\\’) 如: 正则表达式 No [1234] 匹配 No 1, No 2, No 3 和 No 4.

    如果想在中括号中使用一个范围作为列表来匹配字符,可以用连字符 ‘-’ 将范围中的开始字符和结束字符分开。单个字符的字符值确定范围内的相对顺序。如: 正则表达式 No [1-4] = No [1234]

    注意 1. 开始值的Unicode值必须在结束值Unicode值的前面。

    注意 2. [\-]匹配连字符’-', 放在中括号列表的开始或结尾也可起到同样的效果, 如 [-c-f] 匹配 c 至 f 的字符和连字符

    如果需要匹配不属于列表或范围内的任何字符,可以在列表开头加上’^'前缀。如: 正则表达式 No [^1-4] 匹配 No 5 和更大的编号.

    中括号表达式还可进行组合, 如 [A-Za-z0-9] 匹配A-Z, a-z, 0-9 的字符

  • \ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,
    字符 n 匹配字符 n

    \n 匹配换行符

    序列 \\ 匹配 \

    序列 \( 匹配 (

  • | 替换字符, 对|左右的两个项分别匹配进行选择。或者说, 就是逻辑的OR的概念
  • { } 标记限定符表达式的开始。
    (数量)限定字符

    限定字符能够指定正则表达式的某个部分必须出现的次数

    • * 零次或多次匹配前面的字符或子表达式。如,c*f 可以匹配 f 和 ccf。* = {0,}
    • + 一次或多次匹配前面的字符或子表达式。如,c+f 可以匹配 cf 和 ccf,但不匹配 f。+ = {1,}
    • ? 零次或一次匹配前面的字符或子表达式。如,cc?f 可以匹配 cf 或 ccf。? = {0,1}
    • {n} n 是非负整数。正好匹配 n 次。如,c{2}f 可以匹配 ccf。
    • {n,} n 是非负整数。至少匹配 n 次。如,c{2,}f 不匹配 cf,而可以匹配 ccccccf。c{1,} = c+。c{0,} = c*
    • {n,m} m 和 n 是非负整数,其中 n <= m。至少匹配 n 次,至多匹配 m 次。如,c{1,3} 可以匹配 ccf 中的cc。c{0,1} 等效于 c?。

2.2.2 控制字符

  • \a Bell 字符。= 0×07
  • \f 换页符匹配。= 0×0C
  • \n 换行符匹配。= 0×0A
  • \r 匹配一个回车符。= 0×0D
  • \t 制表符匹配。= 0×09
  • \v 垂直制表符匹配。= 0×0B
  • \e ASCII 换码字符。= 0×1B
  • \0dd 八进制换码字符, dd代表八进制数字。
  • \xXXXX或\x{XXXX} 4位十六进制Unicode字符, XXXX代表十六进制数字。
  • \cZ Z-’@’ 控制字符Control-Z, Z为大于等与”@”的ASCII字符

2.2.3 换码字符

  • \w 任一单词字符, 如A-Z, a-z, 0-9, _等, 如 \w\w\w可以匹配 U_4 但不匹配 %^e
  • \W 任一非单词字符, 如 \W\W 可以匹配 *& 但不匹配 7#
  • \s 任一空白字符,包括空格、制表符、换页符、回车符和垂直制表符。= [ \f\n\r\t\v]
  • \S 任一非空白字符. = [^ \f\n\r\t\v]
  • \d 0-9的任一数字字符, 如 \d\d可以匹配 54 但不匹配 a4
  • \D 任一非数字字符. 如 \D\D可以匹配 a4 但不匹配 54
  • \l a-z 之间的任一小写字符, 如 \l\l\l可以匹配 ccf 但不匹配 ccF
  • \L 任一非小写字符, 如 \L\L\L可以匹配 CCF 但不匹配 cCF
  • \u a-z 之间的任一大写字符, 如 \u\u\u可以匹配 CCF 但不匹配 CCf
  • \U 任一非大写字符, 如 \U\U\U可以匹配 ccf 但不匹配 ccF
  • \C 任一字符, = ‘.’
  • \Q 前置引号符, 其后的任意字符均被认为普通字符直至出现后置引号符\E. 同时匹配单引号和双引号
  • \E 后置引号符

2.2.4 转义字符串

表示为[:classname:], 如”[[:space:]]”表示所有的空格字符

  • alnum 任一单词字符和数字字符. = [\w\d]
  • alpha 任何一个单词字符, 如A-Z, a-z, 0-9
  • blank 任一空白字符,包括空格、制表符、换页符、回车符和垂直制表符。= [ \f\n\r\t\v] = \s
  • cntrl 任一控制字符.
  • digit 0-9的任一数字字符, = \d
  • graph 任一图形字符.
  • lower a-z 之间的任一小写字符 =\l
  • print 任一可打印字符 = ‘.’ = \C
  • punct 任一标点符号
  • space 任一空格字符
  • upper a-z 之间的任一大写字符 = \u
  • xdigit 4位十六进制Unicode字符, = \xXXXX
  • word 任何一个单词字符, 如A-Z, a-z, 0-9, _等, = \w
  • unicode 任何一个ASCII值大于255的字符

2.2.5 定位字符

定位字符可以把正则表达式固定到行首或行尾。在Perl正则全集中还能使正则表达式出现在一个单词内、在一个单词的开头或者一个单词的结尾, emeditor只是一个子集, 不包含这个功能。

  • ^ 匹配输入字符串开始的位置。如果设置customize中的”regular expressions can match new line characters”,那么 ^ 还匹配 \n 或 \r 后面的位置。 但在中括号表达式中使用的情况除外,在那种情况下它对字符集求反。
  • $ 匹配输入字符串结尾的位置。如果设置customize中的”regular expressions can match new line characters”,那么 $ 还匹配 \n 或 \r 前面的位置。

3. 分组捕获和替换

分组通常用来捕获特定模式的一组文本, 并用与之后的替换操作, 这也就是将分组和替换结合起来讲解的原因.

最基本的分组构造方式就是(),在左右括号中括起来的部分,就是一个分组;在正则全集中还有如(?<name> )的命名分组方式,这种方式组合了模式在就是对分组的部分进行了命名,这样就可以通过该组的命名来获取信息, 但这种方式在emeditor中不被支持. 以下分别来介绍各种不同的分组:

  • () 组捕获. 这种分组对模式在括号内所捕获的字符进行组合, 并且每个分组捕获的匹配结果都将保存为一个实体以备其后的操作所引用. 甚至在正则全集中还可对前面的分组进行反向引用(这是题外话, emeditor不支持). 举例说明:

    源文本:

    代码:
    site status- online members: 65, online guests: 12

    使用正则表达式:

    代码:
    (members|guests): \d+

    括号中有两个可能的匹配: members 和 guests, 只需要匹配其中任意一个; 其后是冒号和一个空格, 最后匹配至少一个数字. 匹配模式结果如下:

    代码:
    members: 65
    guests: 12

    其中members和guests在两次匹配中被捕捉, 可以在随后的操作中引用.

  • (? 非组捕获. 这种分组仅仅对模式在括号内所匹配的字符进行组合, 模式所匹配的字符将不会作为一个组来捕获. 虽然他也同样成为最终的匹配结果的一部分, 但无法为其后的操作所引用. 同样以上例继续:

    使用正则表达式:

    代码:
    (?:members|guests): \d+

    匹配模式结果同样为:

    代码:
    members: 65
    guests: 12

    但是members和guests仅仅在两次匹配中被分组, 并不被捕获, 也不可以在随后的操作中引用.

    使用非捕获组有其原因和场合. 其一, 从效率上说, 捕获一个分组需要消耗额外的资源和处理时间, 所以不应该捕获不需要使用的数据. 其二, 对模式中有多个捕获组的情况, 对不需要处理的分组进行捕获只会对分组信息造成混乱. 其三, 避免不需要贪婪匹配的场合发生贪婪匹配, 贪婪匹配是正则引擎的一个重要特性, 要说清楚其机理可能还需要另外开一个专题了. 对这一点, 还以上例说明一下:

    使用不带分组的正则表达式:

    代码:
    members|guests: \d+

    匹配模式为:

    代码:
    members
    guests: 12

    这个正则表达式的问题在于, 他匹配的是”members” 或 “guests: \d+”, 这是模式中贪婪”消费”字符引起的. 而通过增加括号进行分组, 使正则引擎将两个匹配选项作为一个组处理, 从而正确匹配其中的一个匹配项.

  • (?=) 正声明组, 非捕获. 此分组中的模式必须出现在声明的右侧, 并且, 这个模式不构成匹配结果的一部分. 举例:

    源文本:

    代码:
    site status- online members: 65, online guests: 12

    使用正则表达式:

    代码:
    \S+(?=\s\d+)

    此模式中规定了\s\d+必须出现在\S+声明的右侧. 也就是说, 在至少一个非空格字符(声明)的右侧必须出现一个空格字符和至少一个数字, 而且只有这个声明构成匹配结果. 匹配模式结果如下:

    代码:
    members:
    guests:

    这两次匹配中不被捕捉.

  • (?!) 负声明组, 非捕获. 此分组中的模式不得出现在声明的右侧, 并且, 这个模式不构成匹配结果的一部分. 还是用上面的例子:

    使用正则表达式:

    代码:
    \d{2}(?!,)

    此模式中规定了”,”不得出现在\d{2}声明的右侧. 也就是说, 在连续两个数字(声明)的右侧不得出现逗号才能被匹配. 匹配模式结果如下:

    代码:
    12

    这两次匹配中不被捕捉.

严格的说, 后面两个分组不能称之为分组, 他们只是模式声明, 他们不能成为匹配结果, 也不能被捕获. 在正则全集中, 还有反向声明分组(?<=)(?), 在emeditor中不被支持.

说到括号的功能, 本来正则中的一个重要指令-条件指令和分组内联设定是不得不说的, 可惜的是… emeditor也同样不支持~~~~

在前面的例子中一直提到匹配之后的操作, 而这个进一步的操作最常见的就是替换. 先继续上面的例子:

源文本:

代码:
site status- online members: 65, online guests: 12

使用搜索正则表达式:

代码:
(members|guests)

和替换正则表达式:

代码:
ccf-\1

匹配模式结果如下:

代码:
members
guests

替换后的文本为:

代码:
site status- online ccf-members: 65, online ccf-guests: 12

其中members和guests在两次匹配中被捕捉, 在随后被引用, 并添加ccf-前缀后替换源文本中的匹配字符.

在匹配模式中的分组匹配结果将按前后顺序被正则引擎分别赋予内部组号, 在替换操作中就可以用\加上这个组号来引用相应的匹配结果. 继续上例:

使用搜索正则表达式:

代码:
(members|guests): (\d{2})

和替换正则表达式:

代码:
ccf-\1 = \2

匹配模式结果如下:

代码:
members: 65
guests: 12

替换后的文本为:

代码:
site status- online ccf-members = 65, online ccf-guests = 12

在emeditor的正则子集中增加了一个特殊的引用: \0 , \0 将引用上次的匹配结果, 继续把:

使用搜索正则表达式:

代码:
\d{2}

和替换正则表达式:

代码:
*\0*

匹配模式结果如下:

代码:
65
12

替换后的文本为:

代码:
site status- online ccf-members: *65*, online ccf-guests: *12*

作为一个编辑软件, emeditor的正则子集中增加了一些替换修饰符:

  • \U 大写修饰. 将其后的所有的字符替换为大写
  • \L 小写修饰. 将其后的所有的字符替换为小写
  • \H 半角修饰. 将其后的所有的字符替换为半角字符. 写到这里, 不得不称许一下emeditor对中文的良好支持, 这个\H至少我是很常用的, 不喜欢看到文本里面都是些123abc之类的全角字符…
  • \F 全角修饰. 将其后的所有的字符替换为全角字符
  • \E 关闭之前的\U, \L, \H, \F修饰.

Permanent Link | Posted in 软件 | Tags on: ,

数字转美元程序2009-02-15 1:09 pm

admin

本程序将数字转换为英文的美元数,如: 输入

./num2eng.pl 1,100,834.10

则输出:

Total: Say US Dollars One Million One Hundred Thundsand Eight Hundred and Thirty-Four and Ten Cents Only.

注意事项:

  1. 整数部分可以使用半角的逗号、空格、单引号、下划线、中划线分隔。
  2. 分隔符的位置可以任意(每3位可,每4位也可),可以任意组合(可以混合使用上述的分隔符)。
  3. 如果使用单引号,请注意在最外边加上双引号以免转义。

完整程序:
本文已浏览446次。 继续阅读… »

Permanent Link | Posted in 杂项 | Tags on: ,

Grep书签2009-02-08 11:43 pm

admin

Grep是终端下一款好用的正则表达式工具,其全名是lobal search regular expression(RE) and print out the line,它最直接的功能是搜索具有指定正则表达式模式的文本文件。当然还可以在不同的场合下有不同的功用。例如,在ubuntu下,我经常使用类似于这样的命令(在windows下,搜索NTFS分区中的文件,我使用Everything,它是速度最快的文件搜索软件,不过只搜索文件名,不搜索文件内容,支持正则表达式):

find | grep -E ‘(mp3|wma)$’

该命令的作用是,以递归的方式寻找当前目录下所有的mp3、wma文件,打印出完整的路径。之所以不用ls,是因为ls不能显示完整路径。之所以在grep后面加”-E”,是为了使用更完整的正则表达式的支持。

我推荐的关于GREP的链接如下:
本文已浏览460次。 继续阅读… »

Permanent Link | Posted in 软件 | Tags on:

[译]正则表达式:从菜鸟到大师2009-02-03 10:06 am

admin

Author: Jan Goyvaerts

Publish Date: 2 Feb. 2009

Blog entry: http://www.regexguru.com/2009/02/from-regex-newbie-to-regex-guru/

Translated By: Rex (http://iregex.org)

Rex注:本文是Jan Goyvaerts为自己的著作《Regular Expression Cookbook》写的序言中的一段。

One of my last tasks for the Regular Expression Cookbook was to write the preface, including my author bio. I told the story of how I went from my first real encounter with regular expressions in 2000, to the expert I am almost a decade later.

《Regular Expression Cookbook》即将完工,剩余的工作之一是作序,包括写我的作者小传。我讲述了自己如何在2000年第一次遭遇正则表达式,并在近乎十年之后才成为专家的经历。

本文已浏览973次。 继续阅读… »

Permanent Link | Posted in 翻译 | Tags on: , , ,

Regular Expression Cookbook 接受预订2009-01-28 10:07 pm

admin

Regex大牛(regexguru)一直在写的一本书《Regular Expression Cookbook》现在可以在Amazon.com, Amazon.co.uk, Amazon.fr, Amazon.de以及其它许多网店预订了。本书有望于2009年5月15日出版,标价US$ 39.99。本文发布时,Amazon.com 提供 34% 的优惠, Amazon.co.uk 提供 10% 的优惠。

本书的最后期限是1月31日,作者在该日期之前提交最后的修改勘误,并将为本书新建网站http://www.regular-expression-cookbook.com/

新闻来源:RegexGuru: Regular Expression Cookbook Available for Pre-Order

Permanent Link | Posted in 新闻 | Tags on: , ,

RegexBuddy3.2.1完全版2009-01-11 2:46 am

admin

感谢网友WNlord提供信息,我有幸下载到了RegexBuddy当前的最新版3.2.1。该版本是零售完全版,可以做生成Portable Installation。不知道RegexBuddy功能的请自行站内搜索。下载地址见文章末尾。
本文已浏览1025次。 继续阅读… »

Permanent Link | Posted in 软件 | Tags on: , ,

使用饭否新版API编写批量抓取饭否消息的程序2009-01-06 10:27 am

admin

我在断断续续地写一款抓饭程序。预想的功能包括:下载、更新饭否消息,搜索,统计。

近日饭否官方释出搜索功能,可以使用关键字搜索自己曾经发布的消息。作离线版的饭否消息管理工具,似乎没有必要。不过,有的网友习惯将饭否消息列到blog上,因此,我的程序还是有用的。

我原来写的程序,时间都消耗在饭否消息的下载、解析上。好在饭否新版API提供了任意页码的饭否消息,大大简化了抓取难度,因此编写一款饭否消息管理工具不再是一件难事。以python语言为例,我把自己的思路写出来,供各位有类似兴趣的朋友参考。

本文已浏览984次。 继续阅读… »

Permanent Link | Posted in 杂项 | Tags on: , , , ,

wordpress UTF8 中文字数统计插件2009-01-02 10:37 pm

admin

最近想在博客中实现这样的功能:“本文字数XXX,继续阅读…”。在网上找了一款Word Count Plugin for WordPress,作者是 Murray Williams,可惜它只能统计英文单词数,却不能统计中文字数。我下载了源码,自己动手修改,实现了想要的功能。修改过程中涉及了PHP语言中如何使用正则表达式来匹配中文,于是我把过程写这在里。

本文已浏览920次。 继续阅读… »

Permanent Link | Posted in 教程 | Tags on: , , ,

正则式软件中的TotalCMD:RegexBuddy2008-12-27 2:39 am

admin

regexbuddy 3.2.0

之前我爱正则表达式已经介绍过,RegexBuddy 是windows下(在linux下可以使用wine调用)一款超强的正则式辅助编写软件。在它的帮助下,你可以轻松编写你所需要的正则表达式,清晰地理解别人写的正则表达式,快速测试正则式与目标文本或文件是否匹配并避免出现错误。它能帮你把正则表达式转换成你所需要的编程语言的格式,帮你收集并详细记录正则式代码库,以便将来重新使用。它还能与你最喜欢的搜索工具、编辑器集成在一起,招之即来。在我所有使用过的正则式软件中,以RegexBuddy为最强,称之为正则式软件中的TotalCMD,毫不为过。

原来本站以留言索取的形式,向诸位同好提供过3.1.0版。在网友那个谁的协助下,我得到了更新一点的版本,3.2.0,附在文末,请按需下载。

本文已浏览1263次。 继续阅读… »

Permanent Link | Posted in 软件 | Tags on:

在Excel VBA中使用正则表达式2008-12-25 11:24 am

admin

在Excel中使用正则表达式|题图|我爱正则表达式

在Excel中使用正则式,需要借助于Excel自带的Visual Basic环境。我查了一下Microsoft Office Excel 2007 Formulas & Functions FOR DUMmIES以及Excel VBA Programming For Dummies,两本书中均没有关于正则表达式的函数,也没有关于如何在VB中使用正则表达式的介绍。不过,我还是在google中使用excel 和regex 作为关键词找到了答案,总结在这里。我没怎么使用过VB,这里的代码只是浅尝辄止式,能够运行而已。本文假设读者有实际操作Excel VBA的经验。

本文已浏览2252次。 继续阅读… »

Permanent Link | Posted in 教程 | Tags on: , ,

PowerGREP3.50完全版下载2008-12-23 10:28 pm

admin

之前我爱正则表达式介绍过一款软件PowerGREP,并以留言索取的形式,向大家发放3.3.3版。今天,在热心网友astek的推荐下,rex下载到了PowerGREP的3.50版,这也是迄今为止的最新版。下载地址见文末。

PowerGREP是一款正则式应用软件,它是grep或egrep的增强版,允许您以直观可视、可撤消的方式,在不同的文件夹内,对不同的文件进行批量的文本搜索、替换。当然,是正则表达式层面上的。详细的介绍可参考这篇文章:windows下的正则式工具介绍之二:powergrep。该篇文章的评论功能已经关闭,如果对该软件有问题,可以在此留言,或集中至正则式中文论坛http://regex.me讨论。

本文已浏览1259次。 继续阅读… »

Permanent Link | Posted in 软件 | Tags on: , , , ,

Just Great Software 动态2008-12-22 9:01 pm

admin

Just Great Softwarehttp://www.just-great-software.com/的著名产品有powergrepregexbuddy。今天该网站释出消息,主要有以下2点:

  • Jan Goyvaerts近来在写一本关于正则表达式的书。目前已经脱稿,有望在2009年4月份由O’Reilly出版。作者坦承,该书或许是关于正则式的最实用的著作。
  • http://www.just-great-software.com/在08年的新产品不多,只对原有的几款产品作了次要升级。好消息是,自07年就开始酝酿的一款新软件的攻坚工作已经完成,会在2009年发布1.0。希望在4月份之前发布。

原文来源:http://www.just-great-software.com/

Permanent Link | Posted in 新闻 | Tags on: , ,

Windows下的正则表达式工具之五——经典的Regulator2008-12-17 11:55 pm

admin

本文介绍的the Regulator 2.0 与上一篇文章介绍的Expresso一样,都是颇有年头的软件:Expresso的最后更新日期似乎是2007年6月30日;the Regulator 2.0的上次更新,更是可追溯到2004年。可是,在没有RegexBuddy的日子里,the Regulator 可算是元老呢!MSDN上有篇文章《Ten Must-Have Tools Every Developer Should Download Now》,介绍了开发者必备的10款工具之一就有the Regulator。作者Roy Osherove在regulator的帮助文件中说,自己的Regulator的创意就来自于Expresso

Regulator的界面,比Expresso要新潮,与以前介绍过的Mtracer有几分相像。 本文已浏览702次。 继续阅读… »

Permanent Link | Posted in 软件 | Tags on: , , , ,

© 我爱正则表达式 Allrights reserved. | Theme: iPost 2.7.2 |Designed By iFire. | Powered by WP. | Entries (RSS) | Comments (RSS).