速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

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

  • 2011-01-21
  • 本文字数:2495 字

    阅读完需:约 8 分钟

【编者按】正则表达式一直是开发者工具箱中趁手的利器,但很多人对此仍是一知半解。这次 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 也会这样处理,但是我并不推荐这样使用,因为它往往会令不理解这特性的人困惑,正则表达式对应的字符串中出现\[如何不会报错?\[和\\[为什么竟然是一样的效果?

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

关于作者

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


感谢张凯峰对本文的策划及审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011-01-21 00:0025069

评论

发布
暂无评论
发现更多内容

WIFI6E moudle-QCN9074+WiFi6 MT7915-support 2.4GHz and 5GHz-M.2-MINI PCIE how to choose?

wifi6-yiyi

wifi6 WIFI6E

Databend 开源周报第 107 期

Databend

【深度学习 | 感知器 & MLP(BP神经网络)】掌握感知的艺术: 感知器和MLP-BP如何革新神经网络 - ARTS 打卡第 二 周

计算机魔术师

人工智能

直播平台源码搭建协议讲解篇:传输控制协议TCP

山东布谷科技

TCP 软件开发 网络协议 直播平台源码 传输控制协议

Apache Paimon 实时数据湖 Streaming Lakehouse 的存储底座

Apache Flink

大数据 flink 实时计算

打造基于AI的一站式节能减碳方案,南洋万邦助力工业园区实现“双碳”目标

飞桨PaddlePaddle

人工智能 paddle 百度飞桨

最好用的Java开发工具:IDEA 2023激活中文+安装教程

胖墩儿不胖y

Mac 软件 Java 开发 java开发工具

Mac电脑数据库管理推荐:DBeaverUltimate 旗舰激活最新版

mac大玩家j

数据库管理 Mac软件 管理数据库 数据库工具

illustrator2023最新版 矢量图形编辑软件ai2023简体中文版下载

mac

Illustrator ai2023 苹果mac 矢量图形编辑软件 illustrator2023

火山引擎DataWind产品可视化能力揭秘

白露为霜

数据可视化 商业智能 BI 分析工具 图表库 BI 报表

学习微服务必推荐的天花板级别微服务架构笔记

小小怪下士

Java 程序员 微服务 springboot

iStat Menus for Mac中文下载附激活码

mac大玩家j

Mac软件 系统检测工具

蓝易云:JAVA使用HTTP代理教程。

百度搜索:蓝易云

Java 云计算 Linux 运维 HTTP

全链路数据湖开发治理解决方案2.0重磅升级,全面增强数据入湖、调度和治理能力

阿里云大数据AI技术

小灯塔系列-中小企业数字化转型系列研究——CRM测评报告

向量智库

华为云classroom赋能--Toolkit系列插件DevSecOps助力开发者提速

华为云PaaS服务小智

DevOps 开发工具 华为云

百度工程师浅析解码策略

百度Geek说

解码 企业号 8 月 PK 榜 生成模型

峰会回顾第7期 | 视窗绘制技术演进和新趋势

OpenHarmony开发者

OpenHarmony

2023中国算力大会,和鲸科技携手生态伙伴共同推动算力创新发展与应用

ModelWhale

AI 算力 云算力 2023中国算力大会

Audition 2021 mac完整版 音频编辑软件audition新功能

mac

苹果mac 音频编辑软件 Windows软件 audition 2021 audition

查询速度最高提升50倍!火山引擎ByteHouse在广告投放领域实践分享

字节跳动数据平台

数据库 大数据 云原生 数仓 企业号 8 月 PK 榜

实时云渲染的关键技术是什么?

Finovy Cloud

云计算 3D 云渲染 实时云渲染

SRE 与开发的自动化协同 -- 生产环境出现 bug 自动生成异常追踪

观测云

异常追踪 智能巡检

一行命令即可启动 Walrus丨入门教程

SEAL安全

企业号 8 月 PK 榜 快速上手 实用教程

数据库国产化应用改造实践

鲸品堂

数据库 国产化 企业号 8 月 PK 榜

高性能网络 SIG 月度动态:ANCK 首次支持 SMCv2.1,virtio 规范支持隧道报文内头部哈希

OpenAnolis小助手

高性能网络 龙蜥社区 anck 龙蜥sig smc

【代码实践】使用FastAPI+Supabase+LangChain开发AI应用

张文平

FastApi 应用开发 Supabase #人工智能 #LangChain

How IPQ9574, IPQ9554, QCN9274, and QCN6274 Qualcomm Chipsets Harness the Full Potential of WiFi7 Features

wallyslilly

WiFi7 ipq9554 qcn9274 qcn6274 ipq9574

正则表达式(一):纠结的转义_Java_余晟_InfoQ精选文章