正则表达式:开发者实用指南

· 12分钟阅读

目录

正则表达式(regex)是开发者工具箱中最强大的工具之一。它们提供了一种简洁、灵活的方式,使用模式描述来搜索、匹配和操作文本。无论您是在验证用户输入、解析日志文件、从API提取数据,还是执行复杂的查找和替换操作,正则表达式知识对于高效开发都是必不可少的。

这份综合指南将带您从基础知识到高级模式,并提供实用的真实示例。最后,您不仅会理解语法,还会知道何时以及如何在项目中有效应用正则表达式。

正则表达式基础

从本质上讲,正则表达式是定义搜索模式的字符序列。可以将其视为描述文本模式的迷你语言。让我们从构成每个正则表达式模式基础的基本构建块开始。

字面字符

最简单的正则表达式是字面字符串。模式hello匹配输入中的确切文本"hello"。大多数字符按字面意思匹配自己,使基本搜索变得简单直接。

但是,某些字符在正则表达式中具有特殊含义,称为元字符。当您想要按字面意思匹配它们时,必须使用反斜杠进行转义:

. ^ $ * + ? { } [ ] \ | ( )

例如,要匹配字面句点,使用\.而不是仅使用.。要匹配美元符号,使用\$

锚点

锚点不匹配字符——它们匹配文本中的位置。它们对于精确的模式匹配至关重要:

示例:模式^Hello$仅匹配恰好包含"Hello"且前后没有其他文本的行。

示例:模式\bcat\b匹配作为完整单词的"cat",但不匹配"category"或"concatenate"中的"cat"。

专业提示:使用锚点防止部分匹配。在验证电子邮件地址或电话号码时,始终使用^$锚定您的模式,以确保整个字符串匹配您的模式,而不仅仅是其中的一部分。

字符类和量词

字符类和量词是正则表达式真正强大的地方。它们允许您匹配字符范围并指定模式应重复多少次。

字符类

字符类匹配定义集合中的任何一个字符。它们用方括号括起来:

您可以组合多个范围:[a-zA-Z0-9]匹配任何字母数字字符。

简写字符类

这些预定义类节省时间并提高可读性:

简写 等效 描述
\d [0-9] 任何数字
\D [^0-9] 任何非数字
\w [a-zA-Z0-9_] 任何单词字符(字母、数字、下划线)
\W [^a-zA-Z0-9_] 任何非单词字符
\s [ \t\n\r\f\v] 任何空白字符
\S [^ \t\n\r\f\v] 任何非空白字符

量词

量词指定前面的元素应匹配多少次:

示例:\d{3}-\d{2}-\d{4}匹配社会安全号码格式,如"123-45-6789"。

示例:colou?r同时匹配"color"和"colour"('u'是可选的)。

贪婪与懒惰量词

默认情况下,量词是贪婪的——它们匹配尽可能多的文本。在量词后添加?使其变为懒惰(非贪婪),匹配尽可能少的文本:

示例:给定文本<div>content</div>,模式<.+>(贪婪)匹配整个字符串,而<.+?>(懒惰)仅匹配<div>

快速提示:在提取分隔符之间的内容(如HTML标签或引号)时,始终使用懒惰量词以避免匹配过多。模式".*?"正确提取带引号的字符串,而".*"会从整行中的第一个引号匹配到最后一个引号。

分组、捕获和反向引用

分组允许您将多个字符视为单个单元,并捕获匹配的文本以供以后使用。它们对于复杂模式和文本提取至关重要。

捕获组

括号()创建捕获组。匹配的文本被存储并可以稍后引用:

(\d{3})-(\d{3})-(\d{4})

此模式匹配电话号码并捕获三个组:区号、前缀和线路号码。在大多数语言中,您可以将这些捕获作为$1$2$3或类似语法访问。

非捕获组

有时您需要分组用于量词或交替,但不需要捕获文本。使用(?:...)表示非捕获组:

(?:https?|ftp)://[^\s]+

这匹配以http、https或ftp开头的URL,而不单独捕获协议。当您不需要捕获的文本时,非捕获组更高效。

命名捕获组

命名组使您的正则表达式更具可读性和可维护性。语法因语言而异:

示例:

(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})

这匹配日期并为年、月、日创建命名捕获,使您的代码更具自我说明性。

反向引用

反向引用允许您匹配模式中先前捕获的相同文本:

示例:\b(\w+)\s+\1\b匹配重复的单词,如"the the"或"is is"。

示例:(['"])(.*?)\1匹配单引号和双引号字符串,确保结束引号与开始引号匹配。

交替

管道字符|充当OR运算符。它通常与组一起使用:

(cat|dog|bird)

这匹配"cat"、"dog"或"bird"。注意交替顺序——正则表达式引擎从左到右尝试替代项,并在第一次匹配时停止。

前瞻和后顾断言

环视断言是零宽度断言,根据前后内容匹配位置,而不将该文本包含在匹配中。它们对于复杂的匹配场景非常强大。

前瞻断言

前瞻检查当前位置之后的内容:

示例:\d+(?= dollars)匹配后跟" dollars"的数字,但不在匹配中包含" dollars"。

示例:^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$验证包含至少一个大写字母、一个小写字母、一个数字且至少8个字符的密码。

后顾断言

后顾检查当前位置之前的内容:

示例:(?<=\$)\d+匹配前面有美元符号的数字,但不在匹配中包含美元符号。

示例:(?<!un)happy匹配"happy"但不匹配"unhappy"。

专业提示:环视断言非常适合验证场景,您需要检查多个条件而不消耗字符。当您需要根据上下文匹配某些内容但只想提取特定部分时,它们也是必不可少的。

实用环视示例

从电子邮件中提取域名而不包含@符号:

(?<=@)[a-zA-Z0-9.-]+

匹配后面没有逗号的单词:

\b\w+\b(?!,)

查找前面没有减号的数字(仅正数):

(?<!-)\b\d+\b

常见模式和实际示例

让我们探索经过实战检验的常见开发任务正则表达式模式。这些模式已准备好用于生产,并处理您在实际应用程序中会遇到的边缘情况。

电子邮件验证

一个在严格性和实际使用之间取得平衡的实用电子邮件模式:

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

此模式允许常见的电子邮件格式,同时防止明显错误。对于符合RFC的验证,请考虑使用专用库——完整的RFC 5322正则表达式超过6,000个字符。

URL匹配

匹配带有可选www的HTTP/HTTPS URL:

https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)

对于捕获大多数URL的更简单版本:

https?://[^\s]+

电话号码

具有灵活格式的美国电话号码:

^(\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$

这匹配以下格式:

日期格式

ISO 8601日期格式(YYYY-MM-DD):

^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$

美国日期格式(MM/DD/YYYY):

^(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{4}$

IP地址

IPv4地址验证:

^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$

这确保每个八位字节在0到255之间。

信用卡号码

基本信用卡格式(带有可选空格或破折号):

^\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}$

请记住使用Luhn算法进行实际验证——正则表达式仅检查格式。

十六进制颜色

匹配带有可选#前缀的十六进制颜色代码:

^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$

这匹配6位(#FF5733)和3位(#F57)格式。

用户名验证

带有下划线和连字符的字母数字用户名,3-16个字符:

^[a-zA-Z0-9_-]{3,16}$

密码强度

要求至少8个字符、一个大写字母、一个小写字母、一个数字和一个特殊字符:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&
We use cookies for analytics. By continuing, you agree to our Privacy Policy.