正则表达式入门
如何使用正则表达式
搜索和替换是正则表达式的两种基本用途,下面是两个例子:
- 搜索
假设一个需求是要把
car
、CAR
、Car
或CaR
都找出来,同时要确保scar
、carry
和incarcerate
之类的单词不会被匹配到。
那么对应的语句为:
1 | \b[Cc][Aa][Rr]\b |
当然,一些高级的编辑器提供了不区分大小写以及 Match Only Whole World
(仅匹配整个单词)的选项,但还有许多编辑器不具备这一功能,而你往往无法正在你编辑的文档里做出这种调整。使用正则表达式而不是纯文本 car
就可以解决这个问题。
- 替换
把 URL 地址字符串替换为真正可点击的 URL。
例如:原始的 URL 为:https://convivae.top/
替换后的结果为
1 <A HREF=https://convivae.top>https://convivae.top/</A>
这需要先把相关文本里的 URL 地址字符串找出来(比如说搜索以 http://
或 https://
开头、以句号、逗号、空白字符结尾的字符串),再把找到的 URL 地址字符串替换为 html 语言的 <A HREF=...>...</A>
元素。
什么是正则表达式
定义:简单地说,正则表达式是用来匹配和处理文本的字符串。
正则表达式并不是一种完备的程序设计语言,甚至都算不上是一种直接安装并运行的程序。更准确地说,正则表达式语言是内置于其它语言或软件产品里的“迷你”语言。现在几乎所有的语言或工具都支持正则表达式,但是正则表达式与你正在使用的语言或工具可以说毫无相似之处。正则表达式虽然也被称为一种语言,但它与人们对语言的印象相去甚远。
说完这些掌故,我们再来看一些例子,它们都是合法的正则表达式:
Ben
.
www\.convivae\.com
[a-zA-Z0-9_.]*
<[Hh]1>.*</[Hh]1>
\r\n\r\n
\d{3,3}-\d{3,3}-\d{4,4}
请注意,语法是正则表达式最容易掌握的部分,真正的挑战是学会如何运用那些语法把实际问题分解为一系列正则表达式并最终解决。与学习其他程序设计语言一样,只靠读书是学不会如何灵活运用语法正则的,你必须通过亲身实践才能真正掌握它们。
使用正则表达式
- 正则表达式的使用方法和具体功能,在不同的应用程序/语言中各有不同。
- 并非所有的正则表达式实现都是一样的。在不同的应用程序/语言里,正则表达式的语法和功能往往会有明显(有时也不那么明显)的差异
文章 常见应用软件和编程语言中的正则表达式 对支持正则表达式的许多应用程序和语言在这方面的细节进行了汇总。在继续下面的学习之前,你应该先熟悉一下,看看你们正在使用的应用程序或语言在正则表达式方面有哪些与众不同之处。
在继续学习之前,你还用该了解以下几个事实:
- 在使用正则表达式的时候,你将发现几乎所有的问题都有不止一种解决方案。它们有的比较简单,有的比较快速,有的兼容性好,有的功能更全。这么说吧,在编写正则表达式的时候,只有对、错两种选择的情况是很少见的——同一个问题往往会有多种解决方案。
- 正如前面讲的那样,正则表达式的不同实现往往会有所差异。在后面的内容中,已经尽了最大的努力来保证实例能适用于尽可能多的实现;但有些差异和不兼容是无法回避的,针对这种情况,文中都尽可能地进行了注明。
- 与其他编程语言一样,学习正则表达式的关键是实践,实践,再实践,强烈建议在学习后面的内容时能够亲自实践每一个示例。
匹配单个字符
匹配纯文本
Ben
是一个正则表达式。因为本身是纯文本(甚至可以只包含纯文本)。当然,像这样使用正则表达式是一种浪费,但它作为我们学习正则表达式的起点还是很不错的。一个例子:
文本:
1 | Hello, my name is Ben. This is my article. |
正则表达式:
1 | my |
结果:
Hello, my name is Ben. This is my article.
分析:
这里使用的正则表达式是纯文本,它将匹配原始文本里的 my,它在原始文本里找到了两个结果。
- 注意,绝大多数正则表达式引擎的默认行为是只返回第一个匹配结果。具体到上面那个例子,它只会返回原始文本里的第一个
my
。 - 那么怎样才能把两个或更多个匹配结果都找出来呢?绝大多数的正则表达式的实现都提供了一种能够把所有的匹配结果全部找出来的机制。比如说,在 JavaScript 里,可选的 g(意思是 global,全局)标志将返回一个包含着所有匹配的结果数组。使用不同语言或工具请查阅文章 常见应用软件和编程语言中的正则表达式。
- 正则表达式是区分大小写字母的,所以 my 不能匹配 My。绝大多数的正则表达式的实现也支持不区分大小写的匹配操作。比如,JavaScript 用户可以用 i 标志来强制执行一次不区分字母大小写的搜索。使用不同语言或工具请查阅文章 常见应用软件和编程语言中的正则表达式。
匹配任意字符
在正则表达式里,特殊字符(或字符集合)用来给出要搜索的东西。.
字符(英文句号)可以匹配任何一个单个的字符。
注:正则表达式里的
.
字符相当于 DOS 的?
字符,也相当于 SQL 里的_
(下划线)字符。
于是,用正则表达式 c.t
进行搜索将匹配到 cat
和 cot
(还能匹配到一些毫无意义的单词)
例一
文本:
sales.xls
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式:
1 | sales. |
结果:
sales.xls
sales1.xls
orders3.xls
sales2.xls
sales3.xlsapac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析:
正则表达式 sales.
将把由字符串 sales 和另外一个字符构成的文件名查找出来。9个文件里有四个与这个模式(pattern)相匹配。
- 人们常用“模式”表示实际的正则表达式
- 正则表达式可以用来匹配包含着字符串内容的模式。匹配的并不总是整个字符串,而是与某个模式相匹配的字符,即使他们只是整个字符串的一部分。在上面的例子里,我们使用的正则表达式并不能匹配整个文件名
.
能够匹配任何一个单个的字符,也包括.
本身,故这个模式也与sales.
相匹配
例二
文本:
sales.xls
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式:
1 | .a. |
结果:
sal.es.xls
sal.es1.xls
orders3.xls
sales2xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析:
该模式将与第二个字符是 a
的任意三个字符匹配
匹配特殊字符
思考一个问题:既然 .
是一个能够与任何一个单字符相匹配的特殊字符,那么怎样才能搜索 .
本身呢?这时候就要想办法来告诉正则表达式你需要的是 .
字符本身而不是它在正则表达式中的特殊含义。
为此,你必须在 .
的前面加上一个 \
(反斜杠)字符来对它进行转义。 \
是一个元字符(metacharacter,表示“这个字符有特殊含义”,而不是字符本身含义)
当然,如果要搜索
\
本身,我们仍然可以用\
进行转义,相应的正则表达式是两个连续的反斜杠字符\\
再一次验证刚才的例子:
文本:
sales.xls
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式:
1 | .a.\.xls |
结果:
sales.xls
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析:
这个例子是把以 na
(表示北美)或 sa
(表示南美)开头的文件(不管它们后面跟着一个什么数字)找出来。
第一个 .
匹配 n
(在前两个匹配结果里)或 s
(在第三个匹配结果里),第二个 .
匹配 1
或 2
。接下来,\.
匹配文件名与扩展名之间的分隔符 .
本身,最后的 xls
匹配它本身。
- 我们刚才讲过,
.
可以匹配任意一个字符,这一说法并非绝对准确。在绝大多数的正则表达式实现里,.
只能匹配除换行符以外的任何单个字符。
参考书目
(美国)Ben Forta. 正则表达式必知必会. 北京:人民邮电出版社, 2015.1.