正则表达式(Regular Expression,简称 regex 或 regexp)是一种强大的文本处理工具,它使用一种特殊的字符串来描述、匹配一系列符合某个句法规则的字符串。
你可以把它想象成一个 超级通配符,普通的通配符(如 * 代表任意字符)功能有限,而正则表达式则能定义极其复杂和精确的文本模式,从简单的单词匹配到复杂的结构化数据提取,无所不能。
例如,您很可能使用 ? 和 * 通配符来查找硬盘上的文件。? 通配符匹配文件名中的 0 个或 1 个字符,而 * 通配符匹配零个或多个字符。像 data(\w)?\.dat 这样的模式将查找下列文件:
data.dat
data1.dat
data2.dat
datax.dat
dataN.dat使用 * 字符代替 ? 字符扩大了找到的文件的数量。data.*\.dat 匹配下列所有文件:
data.dat
data1.dat
data2.dat
data12.dat
datax.dat
dataXYZ.dat尽管这种搜索方法很有用,但它还是有限的。通过理解 * 通配符的工作原理,引入了正则表达式所依赖的概念,但正则表达式功能更强大,而且更加灵活。
正则表达式的使用,可以通过简单的办法来实现强大的功能。下面先给出一个简单的示例:
^[0-9]+abc$我们在写用户注册表单时,只允许用户名包含字符、数字、下划线和连接字符 -,并设置用户名的长度,我们就可以使用以下正则表达式来设定。
^[a-zA-Z0-9_-]{3,15}$
^ 表示匹配字符串的开头。[a-zA-Z0-9_-] 表示字符集,包含小写字母、大写字母、数字、下划线和连接字符 -。{3,15} 表示前面的字符集最少出现 3 次,最多出现 15 次,从而限制了用户名的长度在 3 到 15 个字符之间。$ 表示匹配字符串的结尾。以上的正则表达式可以匹配 runoob、runoob1、run-oob、run_oob, 但不匹配 ru,因为它包含的字母太短了,小于 3 个无法匹配。也不匹配 runoob$, 因为它包含特殊字符。
匹配以数字开头,并以 abc 结尾的字符串。:
var str = "123abc";
var patt1 = /^[0-9]+abc$/;
document.write(str.match(patt1));以下标记的文本是获得的匹配的表达式:
123abc\d 匹配任意数字字符,\w 匹配任意字母数字字符,. 匹配任意字符(除了换行符)等。*:匹配前面的模式零次或多次。+:匹配前面的模式一次或多次。?:匹配前面的模式零次或一次。{n}:匹配前面的模式恰好 n 次。{n,}:匹配前面的模式至少 n 次。{n,m}:匹配前面的模式至少 n 次且不超过 m 次。[ ]:匹配括号内的任意一个字符。例如,[abc] 匹配字符 "a"、"b" 或 "c"。[^ ]:匹配除了括号内的字符以外的任意一个字符。例如,[^abc] 匹配除了字符 "a"、"b" 或 "c" 以外的任意字符。^:匹配字符串的开头。$:匹配字符串的结尾。\b:匹配单词边界。\B:匹配非单词边界。( ):用于分组和捕获子表达式。(?: ):用于分组但不捕获子表达式。\:转义字符,用于匹配特殊字符本身。.:匹配任意字符(除了换行符)。|:用于指定多个模式的选择。从技术上讲,正则表达式是一个由普通字符(例如字母 a 到 z)和特殊字符(称为元字符)组成的字符串,这个字符串构成了一个 搜索模式(pattern),该模式被用来在文本中进行搜索、匹配、替换或分割操作。
正则表达式主要有三大用途:
YYYY-MM-DD 统一改为 MM/DD/YYYY。正则表达式几乎渗透在编程和日常文本处理的方方面面。下面是一些最常见的应用场景:
这是正则表达式最经典的应用之一,确保用户输入的数据符合预期的格式。
username@domain.com。2023-12-25 或 12/25/2023 等有效格式。在大量文本中快速定位信息。
ERROR 或 WARN 级别的记录。function xxx(...))或特定变量名。批量修改文本内容,使其规范化。
12345678901 格式化为 123-4567-8901。***,如 110101199001011234 -> 110101********1234。从非结构化的文本中提取结构化的数据。
href="...") 或图片地址 (src="...")。key = value 格式的配置文件。¥100.50 或 $99.99)。使用复杂的规则,而不仅仅是单个字符,来分割字符串。
,、;、\t)来解析 CSV 或 TSV 数据。下面的流程图概括了正则表达式在数据处理中的核心工作流程:
正则表达式的祖先可以一直上溯至对人类神经系统如何工作的早期研究。Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。
1951 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为《神经网事件的表示法》的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为正则集的代数的表达式,因此采用正则表达式这个术语。
随后,发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是 Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的 grep 编辑器。
大致发展历史如下:
目前,正则表达式已经在很多软件中得到广泛的应用,包括 *nix(Linux, Unix等)、HP 等操作系统,PHP、C#、Java 等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。
| 命令或环境 | . | [ ] | ^ | $ | \( \) | \{ \} | ? | + | | | ( ) |
| vi | √ | √ | √ | √ | √ | |||||
| Visual C++ | √ | √ | √ | √ | √ | |||||
| awk | √ | √ | √ | √ | awk是支持该语法的,只是要在命令 行加入 --posix or --re-interval参数即可,可见 man awk中的interval expression | √ | √ | √ | √ | |
| sed | √ | √ | √ | √ | √ | √ | ||||
| delphi | √ | √ | √ | √ | √ | √ | √ | √ | √ | |
| python | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
| java | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
| javascript | √ | √ | √ | √ | √ | √ | √ | √ | √ | |
| php | √ | √ | √ | √ | √ | |||||
| perl | √ | √ | √ | √ | √ | √ | √ | √ | √ | |
| C# | √ | √ | √ | √ | √ | √ | √ | √ |
下面是一个主流编程语言中正则表达式支持的对比:
| 编程语言 | 支持方式 | 常用类/模块 | 简单示例(匹配数字) |
|---|---|---|---|
| JavaScript | 语言原生支持 | RegExp 对象,或使用字面量 /.../ | /\d+/ 或 new RegExp("\\d+") |
| Python | 标准库 re 模块 | re 模块 | re.compile(r"\d+") |
| Java | 标准库 java.util.regex 包 | Pattern 和 Matcher 类 | Pattern.compile("\\d+") |
| PHP | 内置 PCRE 函数 | preg_ 系列函数(如 preg_match) | preg_match("/\d+/", $text) |
| C# | System.Text.RegularExpressions 命名空间 | Regex 类 | new Regex(@"\d+") |
| Go | 标准库 regexp 包 | regexp 包 | regexp.MustCompile(\d+) |
| Ruby | 语言原生支持,核心类 | Regexp 类 | /\d+/ |