正则表达式简介

201 阅读5分钟

原文:An Introduction to Regular Expressions

正则表达式(通常称为 regex)是指定模式的字符串或字符序列。你可以把它看作一个搜索字符串 - 但拥有超能力!

在文本编辑器或文字处理程序中进行简单的搜索可以让你找到简单的匹配项。正则表达式也可以执行这些简单的搜索,但它更进一步,允许你搜索模式(pattern),例如两个数字后跟一个字母,或三个字母后跟一个连字符。

这种模式匹配允许你执行有用的操作,例如验证字段(电话号码、电子邮件地址)、检查用户输入、执行高级文本操作等等。

使用本教程的 下载资源 链接下载正则表达式备忘录 PDF 和 Swift Playground 进行练习。你可以打印备忘录并在开发时将其用作参考。使用包含示例的 Swift Playground 来尝试多个不同的正则表达式。本教程和后续教程中出现的所有正则表达式示例都在该 Playground 中提供了源码,因此请务必查看它们。

基础知识/简介

如果你对正则表达式一无所知,而且很好奇这到底是怎么回事,这里有个简单的解释:正则表达式提供了一种方法,可以搜索给定的文本文档以找到与特定模式匹配的内容,并且可以根据这些匹配进行文本更改。有很多关于正则表达式的优秀书籍和教程,你可以在本教程的结尾找到一个简短的列表。

正则表达式 Playground

在本教程中,你将创建许多正则表达式。如果你想在使用它们时直观地尝试它们,那么 Swift Playground 是一个很好的方法!

你下载材料中的 Playground 顶部包含许多功能,可高亮显示一段文本中正则表达式的搜索结果、在 Playground 的结果窗格中显示匹配项或组的列表,以及替换文本。不过现在不用担心这些方法的实现;你可以在下一个教程中了解它们。相反,请向下滚动到 “Basic Examples” 和 “Cheat Sheet” 部分,然后按照示例进行操作。

在 Playground 的结果侧栏中,你将在每个示例旁边看到匹配列表。对于 “高亮显示” 示例,你可以将鼠标悬停在结果上并单击眼睛或空圆圈图标以显示搜索文本中高亮显示的匹配项。

稍后你将学习如何创建 NSRegularExpression,但现在你可以使用这个 Playground 来了解各种正则表达式的工作原理,并尝试你自己的模式。

示例

让我们从几个简短的示例开始,向你展示正则表达式是什么样的。

下面是匹配单词 “jump” 的正则表达式示例:

jump

这就像正则表达式一样简单。你可以使用 iOS 中提供的一些 API 来搜索文本字符串中与此正则表达式匹配的任何部分 - 一旦找到匹配项,你就可以找到它的位置或替换文本。


这是一个稍微复杂一点的例子 —— 这个例子匹配单词 “jump” 或 “jumps”:

jump(s)?

这是使用正则表达式中可用的一些特殊字符的示例。括号创建了一个组(group),问号表示 “匹配前一个元素(本例中的组)0 或 1 次”。


现在来看一个非常复杂的例子。它匹配一对开始和结束 HTML 标记以及之间的内容。

<([a-z][a-z0-9]*)\b[^>]*>(.*?)</\1>

哇,看起来很复杂,是吗? :] 别担心,你将在本教程的其余部分中了解此正则表达式中的所有特殊字符,当你完成后,你将了解其工作原理! :]

如果你想了解有关前面的正则表达式的更多详细信息,请查看此讨论以获取解释。

注意:在实际使用中,你可能不应该单独使用正则表达式来解析 HTML。请改用标准 XML 解析器!

总述

在继续之前,了解一些有关正则表达式的核心概念非常重要。

文字字符(Literal characters)是最简单的正则表达式。它们类似于文字处理器或文本编辑器中的 “查找” 操作。例如,单字符正则表达式 t 将查找所有出现的字母 “t”,正则表达式 jump 将查找所有出现的 “jump”。非常简单!

就像编程语言一样,正则表达式语法中也有一些保留字符,如下所示:

  • [
  • ()
  • \
  • *
  • +
  • ?
  • {}
  • ^
  • $
  • .
  • | 管道
  • /

这些字符用于高级模式匹配。如果要搜索这些字符之一,则需要使用反斜杠对其进行转义。例如,要搜索文本块中的所有句号,正则表达式不是 .,而是 \.

每个环境,无论是 Python、Perl、Java、C#、Ruby 还是其他环境,在正则表达式的实现中都有特殊的细微差别。Swift 也不例外!

Objective-C 和 Swift 都要求你转义文字字符串中的特殊字符(即在它们前面加上反斜杠 \ 字符)。其中一个特殊字符就是反斜杠本身!由于用于创建正则表达式的模式也是字符串,因此这会增加复杂性,因为在使用 StringNSRegularExpression 时需要转义反斜杠字符

这意味着在你的 Swift(或 Objective-C)代码中,标准的正则表达式语法 \. 应该描述为 \\.

将上述概念简化为要点:

  • 字面量 \\. 定义了一个如下所示的字符串:\.
  • 正则表达式 \. 将匹配单个句号。

捕获括号(Capturing parentheses)用于对模式的一部分进行分组。例如,3(pm|am) 将匹配文本 “3 pm” 以及文本 “3 am”。这里的管道字符 (|) 的作用类似于 OR 运算符。你可以在正则表达式中包含任意数量的管道字符。例如,(Tom|Dick|Harry) 是与这三个名称中的任何一个匹配的有效模式。

当你需要选择性地匹配某个文本字符串时,使用括号进行分组会派上用场。假设你在某些文本中查找 “November”,但用户可能将该月份缩写为 “Nov”。你可以将模式定义为 Nov(ember)?,其中捕获括号后的问号表示括号内的内容是可选的。

这些括号称为 “捕获(capturing)”,因为它们捕获匹配的内容并允许你在正则表达式中的其他位置引用它。

例如,假设你有字符串 “Say hi to Harry”。如果你创建了一个搜索和替换的正则表达式,将任何出现的 (Tom|Dick|Harry) 替换为 that guy $1,结果将是 “Say hi to that guy Harry”。 $1 允许你引用前面规则的第一个捕获组。

捕获组和非捕获组(non-capturing groups)是一些高级主题。你将在后续教程中遇到捕获组和非捕获组的示例。

字符类(Character classes)表示一组可能的单字符匹配。字符类出现在方括号([])之间。

例如,正则表达式 t[aeiou] 将匹配 “ta”、“te”、“ti”、“to” 或 “tu”。方括号内可以有任意多个可能的字符,但请记住,集合中的任何单个字符都会匹配。 [aeiou] 看起来像五个字符,但它实际上意味着 “a” 或 “e” 或 “i” 或 “o” 或 “u”。

如果字符连续出现,你还可以在字符类中定义范围。例如,要搜索 100 到 109 之间的数字,正则表达式将为 10[0-9]。这将返回与 10[0123456789] 相同的结果,但使用范围使你的正则表达式更加清晰且更易于理解。

但字符类并不限于数字 - 你可以对字符执行相同的操作。例如,[a-f] 将匹配 “a”、“b”、“c”、“d”、“e” 或 “f”。

字符类通常包含你要匹配的字符,但是如果你想明确不匹配某个字符怎么办?你还可以定义以 ^ 字符开头的否定字符类。例如,模式 t[^o] 将匹配 “t” 和其他字符(“to” 的单个实例除外)的任意组合。

NSRegularExpressions 备忘录

正则表达式是一个很好的例子,它展示了简单语法最终可以形成非常复杂的结构!即使是最好的正则表达式高手也会为那些奇怪的边缘情况随时准备一张备忘录。

官方 raywenderlich.com 正则表达式备忘单 PDF 包含在可通过本教程顶部或底部的“下载材料”按钮获取的下载材料中。

此外,下面是备忘录的缩略摘要,其中包含一些帮助你入门的附加说明:

  • . 匹配任何字符。p.p 匹配 pop、pup、pmp、p@p 等。
  • \w 匹配任何“类似单词”的字符,包括数字、字母和下划线集,但不匹配标点符号或其他符号。 hello\w 将匹配“hello_”、“hello9”和“helloo”,但不匹配“hello!”
  • \d 匹配一个数字,在大多数情况下表示 [0-9]\d\d?:\d\d 将匹配时间格式的字符串,例如“9:30”和“12:45”。
  • \b 匹配单词的开始或结束,例如空格和标点符号。 to\b 将匹配“to the Moon”和“to!”中的“to”,但不会匹配“tomorrow”。 \b 对于“整个单词”类型匹配很方便。
  • \s 匹配空白字符,例如空格、制表符和换行符。 hello\s 将匹配“Well, hello there!”中的“hello”。
  • ^ 匹配行首。请注意,这个特定的 ^ 与方括号内的 ^ 不同!例如,^Hello 将匹配字符串“Hello there”,但不匹配“He said Hello”。
  • $ 匹配行尾。例如,end$ 将匹配“It was the end”,但不匹配“the end was around”。
  • * 匹配前一个元素0次或多次。 12*3 将匹配 13、123、1223、122223 和 1222222223
  • + 匹配前一个元素 1 次或多次。 12+3 将匹配 123、1223、122223、1222222223,但不匹配 13。
  • 大括号 {} 包含最小和最大匹配数。例如,10{1,2}1 将匹配“101”和“1001”,但不会匹配“10001”,因为最小匹配数为 1,最大匹配数为 2。 He[Ll]{2,}o 将匹配“HeLLo”和“HellLLLllo”以及任何带有大量 L 的“hello”的愚蠢变体,因为最小匹配数为 2,但最大匹配数未设置 —因此是无限的!

这足以让你开始!

是时候开始亲自尝试这些示例了,因为它们都包含在上面提到的 Playground 中。

何去何从?

以下是有关正则表达式的一些有用资源的简短列表:

请务必使用本教程顶部或底部的“下载材料”按钮下载正则表达式备忘单 PDF 和 Playground。

前往我们的 NSRegularExpression 教程,了解如何在 Swift 代码中使用正则表达式! :]