`
carvin
  • 浏览: 209879 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【转】正则表达式(一):纠结的转义

    博客分类:
  • java
阅读更多

【编者按】正则表达式一直是开发者工具箱中趁手的利器,但很多人对此仍是一知半解。这次InfoQ中文站有幸邀请到来自盛大创新院的余晟,开辟《正则表达式》的专栏,为读者讲解正则表达式的一些技巧和概念。他还是《精通正则表达式》和《技术领导之路》的译者。


用过正则表达式的人都知道,正则表达式中有一类叫做“元字符(meta-character)”的特殊符号,它们并不匹配自身对应的字符,而具有其他的含义。比如脱字符『^』表示“定位到字符串/行的开头”,加号『+』表示“之前的元素重现1次以上。如果需要匹配这些字符本身,需要用反斜线来转义,匹配『^』就应该用\^,匹配『+』就应该用\+。

看起来有点麻烦,但这样的元字符并不多:^$()*+?.[\{|

 

元字符

说明

举例

^

匹配整个字符串的起始位置,或者行的起始位置,如果在字符组内部,则表示排除型(negative)字符组

^Start

$

匹配整个字符串的结束位置,或者行的结束位置

End$

()

分组,提供反向引用(gourp1) \1或多选分支

(ab)+

* + ?

量词,限定之前元素出现的次数

a+ (ab)+

.

默认情况下匹配换行符之外的任意字符,在多行模式下可以匹配换行符

[

字符组的起始符号

[0-9]

\

反斜线用来表示转义序列,或去掉元字符的转义

\1

{

重现限定符的开始

{2, 6}

|

划分多选分支(括号没有出现时,可以想象括号出现在整个表达式最外层)

Tom|Jerry

 

你或许注意到了,这些元字符并不是“对称”出现的,比如与开方括号 [ 对应的闭方括号 ],与开花括号 { 对应的闭花括号 } ,这两个字符是否元字符,需要依据具体正则表达式的情况确定,我们以闭方括号]的情况为例(}的情况与此类似):如果之前能找到与之对应的元字符开方括号[,则]作为元字符出现,否则,作为普通字符出现。

 

字符串 \ 表达式

[ab]]

ab]

a]

ab]

 

另外,因为方括号本身可以表示字符组『[0-9]』,所以在字符组内部的闭方括号在任何情况下都要转义,否则类似『[]]』的正则表达式会出现二义性,造成识别错误。

如果需要匹配方括号内(包括方括号),至少包含一个字符的字符串(比如[text]),所用的正则表达式就应该是:『\[[^\]]+]』。

看明白了吗?『\[』匹配开方括号,然后用一个排除型字符组匹配“除闭方括号 ] 之外的任意字符(注意,在字符组内部,闭方括号 ] 一定需要转义),用『+』表示它至少要出现一次以上,最后用一个『]』匹配闭方括号。

下面用代码来验证,以python为例:

import re #为使用正则表达式,必须首先导入re

>>> re.search('^\[[^\]]+]$', '[abcdefg]') #进行数据验证时,在表达式首尾加上^和$是好习惯

<_sre.SRE_Match object at 0x7ff3bc5e75e0>

>>> re.search('^\[[^\]]+]$', '[]')

>>> 

看来确实没有问题,下面用Java试试。直接调用Java中的string.matches(regex)方法,观察返回的boolean值:

"[]".matches("^\[[^\]]+]$")

但是却出现了编译错误:invalid escape sequence。这是为什么呢?在Python中我们并没有使用raw string(如果使用raw string,就应该用r"^\[[^\]]+]$"),一切正常,可是在Java中为什么会出错呢?

要回答这个问题,就得分清转义的层次和规则。如果你留心观察就会发现,上面我们讲的都是“正则表达式的转义”,比如『\[[^\]]+]』是正确转义的正则表达式。仅仅用做正则表达式,它是绝对没有问题的,但它“不仅仅”是正则表达式,而是“字符串形式给出的正则表达式”——注意到了吗?在表达式两端,各有一个双引号。

回忆一下Java中字符串(String)的规则,其中转义序列(escape sequence)用来表示特殊字符,比如\n表示换行符,\t表示制表符,而\[并不是Java能识别的转义序列,当然要出错了。为了表示“正则表达式中的\[”,我们传递给Pattern.compile()的字符串必须正确表示\[——在字符串中,[ 是不需要转义的,而 \ 是需要转义的,所以在字符串中,应该写做 \\[。

总结一下:

 

字符串的表现层

\\[

字符串的概念层

\[

正则表达式的表现层

\[

正则表达式的概念层

[(非元字符)

 

理解了这一点,就不难理解为什么正则表达式的转义序列在正则表达式中要写两个反斜线了,比如 \+ 要写成 \\+ 。但是 \n 之类的有点特殊,无论你写成 \n 或是 \\n ,结果都是一样,\t之类的情况与此类似。

 

字符串的表现层

\\n

\n

字符串的概念层

\n

换行符

正则表达式的表现层

\[

换行符

正则表达式的概念层

换行符

换行符

 

如果字符串中表示反斜线字符本身(不是用来转义的符号),则需要在正则表达式中写四个反斜线字符。

"\".matches("\\\\"); //true

 

字符串的表现层

\\\\

字符串的概念层

\\

正则表达式的表现层

\\

正则表达式的概念层

\(非元字符)

 

看起来,转义问题似乎就是这样,想明白了也很简单。不过,如果你记忆力比较好,估计会问:为什么在Python中写\[不会报错,而Java中会报错?这确实是个好问题,所以我们把它当成本文的结束。

照道理说,各种语言的转义规则都一样:\n表示换行符,\t表示制表符…… 事实也确实如此,只是Python对字符串的处理更复杂一些:如果一个转义序列不能识别,会直接原样保存到字符串中。也就是说,Python遇到无法识别字符串中的\[,不会报错,而是将它原样“转交”给字符串:

 

字符串的表现层

\[

\\[

字符串的概念层

\[

\[

正则表达式的表现层

\[

\[

正则表达式的概念层

[(非元字符)

[(非元字符)

 

“无法识别的转义序列直接转交字符串”的做法不只Python有,PHP也会这样处理,但是我并不推荐这样使用,因为它往往会令不理解这特性的人困惑,正则表达式对应的字符串中出现\[如何不会报错?\[和\\[为什么竟然是一样的效果?

最好的办法或许还是统一表示法,都写成\\[,既方便与其它语言兼容,也方便大家阅读和理解。

关于作者

余晟,程序员,曾任抓虾网高级顾问,现就职于盛大创新院,感兴趣的方向包括搜索和分布式算法等。翻译爱好者,译有《精通正则表达式》(第三版)和《技术领导之路》,目前正在写作《正则表达式傻瓜书》(暂定名),希望为国内开发同行贡献一本实用的正则表达式教程。

 

原文地址:http://www.infoq.com/cn/news/2011/01/regular-expressions-1

 

分享到:
评论

相关推荐

    正则表达式特殊字符的转义

    正则表达式特殊字符的转义,常用网页特殊字符转义,网络爬虫特殊字符处理

    从零开始学习正则表达式

    正则表达式语法(05): 边界 正则表达式语法(06): 贪婪匹配与非贪婪匹配 正则表达式语法(07): 匹配转义字符 正则表达式语法(08): 引用子表达式 - 也叫反向正则表达式语法(09): 临界匹配 - 也叫"预搜索"正则表达式语法...

    正则表达式-字符转义 .net .xlsx

    正则表达式在。net下的转义符意义 正则表达式是正则表达式引擎尝试匹配输入文本的一种模式。 模式由一个或多个字符文本、运算符或构造组成

    从零开始学习正则表达式.rar

    正则表达式学习基础篇正则表达式语法(01): 关于大小写与中文 正则表达式语法(02): 或者与重复 正则表达式语法(03): 匹配范围 正则表达式语法(04): 常用转义字符与 . 正则表达式语法(05): 边界 正则表达式语法(06): ...

    qt正则表达式测试工具

    Qt正则表达式测试工具,可以直接测试正则表达式是否正确。注意:工具中测试好的表达式,写到代码里面需要加转义字符

    正则表达式 30分钟内让你明白正则表达式是什么,并对它有一些基本的了解,让你可以在自己的程序或网页里使用它。

    30分钟内让你明白正则表达式是什么,并对它有一些基本的了解,让你可以在自己的程序或网页里使用它。 本文目标 如何使用本教程 正则表达式到底是什么东西? 入门 测试正则表达式 元字符 字符转义 重复 字符...

    Python基础入门知识之正则表达式学习 正则表达式30分钟入门教程 共21页.pdf

    三、 正则表达式到底是什么东西? 3 四、 入门 4 五、 测试正则表达式 6 六、 元字符 7 七、 字符转义 9 八、 重复 9 九、 字符类 9 十、 分枝条件 10 十一、 分组 11 十二、 反义 12 十三、 后向引用 12 十四、 零...

    正则表达式三十分钟入门教程

    比较全的正则表达式 本文目标 如何使用本教程 正则表达式到底是什么东西? 入门 测试正则表达式 元字符 字符转义 重复 字符类 分枝条件 反义 分组 后向引用 零宽断言 负向零宽断言 注释 贪婪与懒惰 ...

    正则表达式

    除此之外正则表达式中有一些特殊的字符,这些字符在正则表达式中有特殊的用途,如前面介绍的反斜线(\),如果需要匹配这些字符,必须首先将这些字符转义,也就是再前面添加一个反斜线(\).正则表达式中的特殊字符: 1)...

    正则表达式语法

    所以,在其他的语言中,一个反斜杠\就足以具有转义的作用,而在正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在正则表达式中,两个 \ 代表其他语言中的一个 \,这也就是为什么...

    Java正则表达式处理特殊字符转义的方法

    由于正则表达式定了一些特殊字符,而有时候需要对这些特殊字符进行匹配的话就需要进行转义了,下面这篇文章主要给大家介绍了Java正则表达式处理特殊字符转义的方法,需要的朋友可以参考借鉴,下面来一起看看吧。

    正则表达式30分钟入门

    学习正则表达式快速入门的法宝。 语言深入浅出,举例实用、典型。 1、本文目标 2、如何使用本教程 3、正则表达式到底是什么东西? 4、入门 5、测试正则表达式 6、元字符 7、字符转义 8、重复 9、字符类 10、分枝条件...

    正则表达式中需要转移的字符

    正则表达式中需要转移的字符,列举了在写正则表达式时需要转义的字符

    精通正则表达式~~~

    精通正则表达式第三版 搜集于网络 前言..........I 第1章:正则表达式入门.... 1 解决实际问题... 2 作为编程语言的正则表达式... 4 以文件名做类比... 4 以语言做类比... 5 正则表达式的知识框架... 6 对于...

    MySQL的正则表达式

    MySQL的正则表达式

    正则表达式学习教程

    清除格式 文本格式约定:专业术语 元字符/语法格式 正则表达式 正则表达式中的一部分(用于分析) 对其进行匹配的源字符串 对正则表达式或其中一部分的说明 隐藏边注 本文右边有一些注释,主要是用来提供一些相关信息...

    正则表达式30分钟入门教程

    匹配在本文里可能会有三种意思:一种是形容词性的,比如说一个字符串匹配一个表达式;一种是动词性的,比如说在字符串里匹配正则表达式;还有一种是名词性的,就是刚刚说到的“字符串中满足给定的正则表达式的一部分...

    正则表达式30分钟入门教程 chm

    正则表达式到底是什么东西? 入门 测试正则表达式 元字符 字符转义 重复 字符类 分枝条件 反义 分组 后向引用 零宽断言 负向零宽断言 注释 贪婪与懒惰 处理选项 平衡组/递归匹配 还有些什么东西没...

Global site tag (gtag.js) - Google Analytics