照片由 Bryan Natanael 在 Unsplash 上提供。
这篇博客文章源于我对正则表达式(regex)的沮丧和回避,这种情况持续了很长一段时间。
数月来,我一直拖延学习正则表达式的想法,因为说实话,它们看起来非常令人生畏,尤其是当你第一次遇到它们时。我的意思是,一串字符连在一起,似乎没有任何逻辑可言 —— 没有人有时间处理这些东西!
直到最近我在工作中接到了一项任务,需要从字符串中检索元素,我才真正认识到正则表达式的威力。而事实证明,一旦你理解了基础知识,它其实并不那么糟糕。
因此,在本文中,我将解释什么是正则表达式,介绍一些基本的正则表达式字符,最重要的是,使用几个实际示例演示如何使用 R 编程语言执行正则表达式。具体来说,我们将讨论正则表达式中捕获组的概念。
如果你更喜欢 Python,可以在我的 GitHub 上找到代码的 Python 版本 这里。
什么是正则表达式?
正则表达式既不是库,也不是编程语言。相反,正则表达式是一系列字符,它们指定了任何给定文本(字符串)中的搜索模式。
文本可以包含从字母到数字、从空格字符到特殊字符的任何东西。只要字符串遵循某种模式,正则表达式就足够强大,能够捕获该模式并返回字符串的特定部分。
你需要了解的基本正则表达式字符
现在,在我们深入了解细节之前,我认为首先重要的是我们先了解一些正则表达式的基础知识。
本文稍后的示例将建立在这里阐述的一些主要概念上,即:字符、分组和量词。
字符
- 转义字符:
\
- 任何字符:
.
- 数字:
\d
- 非数字:
\D
- 字符或数字:
\w
- 非字符或数字:
\W
- 空格:
\s
- 非空格:
\S
- 字边界:
\b
- 非字边界:
\B
- 字符串开头:
^
- 字符串结尾:
$
分组
- 匹配方括号内的字符:
[ ]
- 匹配不在方括号内的字符:
[^ ]
- 或:
|
- 捕获组:
( )
量词
- 0 或更多:
*
- 1 或更多:
+
- 0 或 1:
?
- 精确数量的字符:
{ }
- 字符数量范围:
{最小值,最大值}
正则表达式示例
不要担心,如果你现在还不理解上面的正则表达式字符 —— 它们只是我们即将讨论的示例的参考。
在本节中,我们将关注 6 个不同的示例,这些示例将有助于加强你对正则表达式的理解。实际上,我们将关注:
- 2 个数字示例(电话号码和日期)
- 2 个字母示例(姓名和 URL)
- 2 个数字和字母的示例(电子邮件地址和地址)
在开始之前,请确保已安装并加载了 tidyverse 包。
1. 电话号码
假设我们有一个名为 phone 的数据框,其中包含如下电话号码列表:
我们希望将这些电话号码分解为 3 个单独的组件:区号(前 3 个数字)、交换机(接下来的 3 个数字)和线路号码(最后的 4 个数字)。
正如我们所看到的,这里的数字模式并不总是一致的,即它们具有不一致的括号、连字符和空格。然而,借助正则表达式的帮助,我们可以轻松地捕获数字组。
首先,我们需要定义一个正则表达式模式。
pattern <- "\\(?\\d{3}\\)?[[:punct:]]?\\s?\\d{3}[[:punct:]]?\\d{4}"
我们如何逐步解释这个模式?我们一步一步来,从左到右:
.?
0 或 1 个字符,以适应可选的左括号(\\d{3})
3 个数字字符(第一个捕获组,即前 3 个数字).*
0 或更多个字符,以适应可选的右括号、连字符和空格字符(\\d{3})
3 个数字字符(第二个捕获组,即接下来的 3 个数字).*
0 或更多个字符,以适应可选的连字符和空格字符(\\d{4})
4 个数字字符(第三个捕获组,即最后的 4 个数字)
然后,我们可以使用 str_match
函数使用我们定义的正则表达式模式检索捕获组,并将它们放入数据框中的单独列中。
library(tidyverse)
phone %>%
mutate(matches = str_match(number, pattern)) %>%
mutate(area_code = matches[, 2],
exchange = matches[, 4],
line_number = matches[, 6])
输出如下:
2. 日期
假设我们有另一个名为 date 的数据框,其中包含带有不一致分隔符的日期,我们想要提取天、月和年。
使用与我们刚才在电话号码中看到的非常相似的方法,我们需要首先定义一个正则表达式模式,然后将模式与原始日期列进行匹配,最后为每个捕获组创建一个新列。
首先,定义日期的正则表达式模式。
pattern <- "(\\d{2}).(\\d{2}).(\\d{4})"
代码解释:
(\\d{2})
2 个数字字符(第一个捕获组,即天).
单个字符,用于考虑所有特殊字符(\\d{2})
2 个数字字符(第二个捕获组,即月).
单个字符,用于考虑所有特殊字符(\\d{4})
4 个数字字符(第三个捕获组,即年)``` 现在,我们可以匹配模式并为日期创建单独的列,包括日、月和年份。
3. 姓名
到目前为止,我们已经探索了两个只包含数字和特殊字符的字符串示例。现在让我们学习如何捕获单词和字母。
这里有一个名为“names”的数据框,包含人们的姓氏、头衔和名字。
让我们将它们分开,使它们各自拥有自己的单独列。
(\\w+)
一个或多个单词字符(第一个捕获组,即姓氏),
逗号字符\\s
一个空格字符(Mr|Ms|Mrs|Dr)
先生、女士、夫人或博士(第二个捕获组,即头衔).?
标题后面的0或1个句号字符\\s
一个空格字符(\\w+)
一个或多个单词字符(第三个捕获组,即名字)
现在,将它们放入单独的列中。
4. URL
让我们看另一个包含单词和字母的字符串示例。
到现在为止,你应该已经熟悉了这个过程。
(https?)
http或https(第一个捕获组,即架构)://
特定的特殊字符串(www)?
可选的www(第二个捕获组,即子域名).?
0或1个句号字符(\\w+)
一个或多个单词字符(第三个捕获组,即二级域名).
一个句点字符(\\w+)
一个或多个单词字符(第四个捕获组,即顶级域名)/?
0或1个反斜杠字符(\\w+)?
可选的一个或多个单词字符(第五个捕获组,即子目录)
将捕获组分成单独的列,我们得到:
5. 电子邮件地址
利用我们已经掌握的有关正则表达式的知识,现在让我们看看包含字母和数字的两个最终字符串示例。
假设我们在一个名为“email”的数据框中有一个电子邮件列表。
现在,生成一个正则表达式模式来匹配用户名、域名和域名。
([a-zA-Z0-9\\_\\-\\.]+)
一个或多个小写字母、大写字母、数字和特殊字符,包括下划线、连字符和句点(第一个捕获组,即用户名)@
符号([a-zA-Z]+)
一个或多个小写和大写字母(第二个捕获组,即域名).
一个句点字符(.+)
一个或多个字符(第三个捕获组,即域名)
然后,将此正则表达式模式应用于电子邮件列表:
6. 地址
当然,我留下了最好的例子供你参考。这个例子与我在工作中所做的相同。
为了重新创建那个工作片段,我创建了一个名为“address”的数据框,其中包含虚构地址。目标是检索房屋编号、街道名称、郊区、州和邮政编码。
像往常一样,我们需要首先定义一个正则表达式模式。
(\\d*)
0或多个数字字符,因为有些地址没有房屋编号(第一个捕获组,即房屋编号)\\s?
0或1个空格字符(.+)
一个或多个字符(第二个捕获组,即街道名称),
逗号\\s
一个空格字符(.+)
一个或多个字符(第三个捕获组,即郊区)\\s
一个空格字符([A-Z]{2,3})
2或3个大写字母(第四个捕获组,即州)\\s
一个空格字符(\\d{4})
4个数字字符(第五个捕获组,即邮政编码)
将此模式与地址列表匹配,我们得到:
我希望通过本博客文章中演示的6个示例,你不仅能够更好地理解正则表达式的工作原理,更重要的是,能够欣赏其在匹配复杂字符串模式方面的灵活性。
译自:https://towardsdatascience.com/regular-expressions-clearly-explained-with-examples-822d76b037b4
评论(0)