正则表达式 133 例
从写法本身,到电子邮件、日期、地址的校验。每个式子都配了该匹配的例子和不该匹配的例子,而且测试每次都真的跑一遍。
写法28
规定怎样指向单个字符的写法。其余一切都从这里开始。
\d一个数字\D数字以外的任何字符\w字母、数字或下划线\W不是单词字符的任何东西\s一个空白字符\S空白以外的任何字符^.$任意一个字符^[a-z]+$只要英文小写字母^[A-Z]+$只要英文大写字母^[A-Za-z0-9]+$只要字母和数字^[^0-9]+$一个数字都没有的文本^[가-힣]+$只要谚文^[ぁ-んァ-ヶー]+$只要假名^[\u4e00-\u9fff]+$只要汉字^a\.b$点号本身^a/b$斜杠本身\t一个制表符\n一个换行符\r\nWindows 式的换行^\u00e9$用码位写出的字符^Hello以这个词开头的文本world$以这个词结尾的文本^cat$正好只有这个词,别无他物\bcat\b独立成词的位置,不在别的词里\Bcat只在别的词内部的位置^cat$不分大小写的匹配^b每一行的开头,不只是整段的开头^a.b$任意字符,连换行也算重复与分组17
规定重复多少次,以及把哪一段看作一个整体。
^ab*c$零次或多次^ab+c$一次或多次^colou?r$可有可无的一个字母^\d{4}$正好四位数字^\d{2,4}$两位到四位数字^\d{2,}$两位以上的数字<.+?>尽量短地取一个标签^<.+>$尽量长地取一整块^(?:cat|dog)$两个词里的任意一个^(?:ab)+$两个字母一组,重复出现^(\d{3})-(\d{4})$前后两段分别抓出来^(?:\d{3}-)+\d{4}$只分组,不抓取^(?<year>\d{4})-(?<month>\d{2})$起个名字再抓取(\w)\1同一个字符连着出现两次\b(\w+)\s+\1\b同一个词打了两遍^(?:https?://)?example\.com$带不带协议头都行的网址^(?:\d{1,3}\.){3}\d{1,3}$由四段组成的地址前后查看8
只查看前后有什么,并不把它吃掉。叠加条件时用得上。
整串校验44
两端都锚住,整个字符串合上才算通过。输入校验用的就是这类。
^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$一个电子邮件地址^https?://[^\s/$.?#][^\s]*$一个网址^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$一个域名^(?:(?: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)$一个 IPv4 地址^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$不省略写全的 IPv6 地址^(?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}$一个 MAC 地址^(?:6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4})$一个端口号^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$一个 UUID^#(?:[0-9a-f]{3}|[0-9a-f]{6})$十六进制颜色代码^rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)$rgb() 形式的颜色值^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ISO 格式的日期^(?:0[1-9]|[12]\d|3[01])/(?:0[1-9]|1[0-2])/\d{4}$用斜杠写的日期^(?:[01]\d|2[0-3]):[0-5]\d$24 小时制的时刻^(?:0?[1-9]|1[0-2]):[0-5]\d\s?(?:am|pm)$带 am/pm 的时刻^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$完整的 ISO 时间戳^P(?=\d|T\d)(?:\d+Y)?(?:\d+M)?(?:\d+D)?(?:T(?:\d+H)?(?:\d+M)?(?:\d+S)?)?$ISO 格式的时长^\d+\.\d+\.\d+(?:-[0-9a-z.-]+)?(?:\+[0-9a-z.-]+)?$语义化版本号^\d+$不带符号的整数^[+-]?\d+$可以带符号的整数^-?\d+(?:\.\d+)?$可以带小数部分的数^-?\d+(?:\.\d+)?[eE][+-]?\d+$用科学记数法写的数^(?:100(?:\.0+)?|\d{1,2}(?:\.\d+)?)%$0 到 100 之间的百分比^\d{1,3}(?:,\d{3})*$每三位打一个逗号的数^[$€£¥₩]\s?\d{1,3}(?:,\d{3})*(?:\.\d{2})?$带货币符号的金额^[0-9a-f]+$十六进制字符串^[01]+$只由 0 和 1 组成的字符串^[0-7]+$八进制字符串^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$base64 编码的字符串^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*$由两个点分成三段的 JWT^\+[1-9]\d{7,14}$国际标准格式的电话号码^[a-z][a-z0-9_]{2,15}$以字母开头的用户名^[a-z0-9]+(?:-[a-z0-9]+)*$用在网址里的连字词^[^\\/:*?"<>|]+\.[a-z0-9]+$带扩展名的文件名^.+\.(?:jpe?g|png|gif|webp|avif|svg)$图片文件的扩展名^/(?:[^/\0]+/)*[^/\0]*$Unix 风格的路径^[A-Za-z]:\\(?:[^\\/:*?"<>|]+\\)*[^\\/:*?"<>|]*$Windows 路径^</?[a-z][a-z0-9]*(?:\s[^<>]*)?/?>$单个 HTML 标签^\.-?[_a-z][_a-z0-9-]*$CSS 类选择器^M{0,3}(?:CM|CD|D?C{0,3})(?:XC|XL|L?X{0,3})(?:IX|IV|V?I{0,3})$罗马数字^-?(?:90(?:\.0+)?|[1-8]?\d(?:\.\d+)?)$纬度值^-?(?:180(?:\.0+)?|1[0-7]\d(?:\.\d+)?|\d{1,2}(?:\.\d+)?)$经度值^(?:0|[1-9]\d*)$开头不带 0 的数^\d*[02468]$偶数^\s*$一行空白提取与清理36
用来从一段文字里只挑出、或只删掉需要的那部分。
\s+$行尾留下的空格^\s+行首的空格^\s+|\s+$前后两端的空格\s{2,}连着两个以上的空格\n\s*\n两行之间的空行\D+不是数字的部分[^\x00-\x7F]ASCII 之外的字符[\x00-\x1F]看不见的控制字符</?[^>]+>文本里的 HTML 标签<!--[\s\S]*?-->HTML 注释//.*$以两个斜杠开头的注释/\*[\s\S]*?\*/跨越多行的注释"[^"\\]*(?:\\.[^"\\]*)*"双引号里的内容'[^'\\]*(?:\\.[^'\\]*)*'单引号里的内容\[([^\]]+)\]\(([^)]+)\)Markdown 链接^#{1,6}\s+.+$Markdown 标题行(?:^|\s)#([a-z0-9_]+)话题标签(?:^|\s)@([a-z0-9_]{2,})用 @ 提到的名字[?&]([^=&]+)=([^&]*)网址问号后面的参数https?://[^\s<>"]+夹在正文里的网址^https?://([^/:?#]+)从网址里只取域名\.([a-z0-9]+)$文件名的扩展名(?<=[a-z0-9])(?=[A-Z])驼峰写法里词与词的接缝_([a-z])下划线后面的那个字母-([a-z])连字符后面的那个字母(?:^|,)("(?:[^"]|"")*"|[^,]+)用逗号分开的一个字段^([^=]+)=(.*)$用等号分开的名字和值^\s*(\S+)第一个词(\S+)\s*$最后一个词\d+文本里成串的数字\b\w+\b一个一个词\[([^\]]*)\]方括号里的内容\(([^)]*)\)圆括号里的内容[\uD800-\uDBFF][\uDC00-\uDFFF]占两个码元的表情符号(.)\1{2,}同一个字符出现三次以上,\s*([}\]])闭合括号前多出来的逗号怎么看这一页
- 两端加上 ^ 和 $,整个字符串就必须合上;不加,匹配落在文中任何位置都行。用来做输入校验的式子,一定要加锚。
- 圆括号 ( ) 会把括住的部分捕获下来。只是想分组的话写成 (?: ),后面各组的编号才不会往后挪。
- 这里的每个式子都拿它自己的例子跑过。不过「长得像电子邮件」和「真有这个信箱」始终是两回事。
- 开放式重复层层嵌套(比如 (a+)+)时,遇到某些输入耗时会爆炸式增长。把别人的式子粘进代码前,先找找有没有这种形状。
常见问题
Q. 什么是正则表达式?
它是一门小语言,用来描述你想在文字里找的「形状」。写 \d{4} 而不是「四位数字」,程序就能找出每一处符合这个形状的地方。JavaScript、Python、Java 等大多数语言用的写法几乎相同。
Q. 电子邮件的校验式为什么这么短?
完全照标准写的邮件式子长达数千字符,而且照样说不出这个信箱是否真的存在。挡住手滑打错,才是正则表达式能做的事;真正的确认只有发一封验证邮件。
Q. 为什么同一个式子在各语言里略有不同?
骨架一样,细节不同。JavaScript 没有 \A,Python 要单独打开 re.MULTILINE。这里列出的式子都是按在 JavaScript 里原样能跑的形式写的。
Q. 说式子可能很慢,是什么意思?
像 (a+)+ 这样开放式重复嵌在一起时,遇到匹配不上的输入,回溯的路数会爆炸。这时哪怕很短的字符串也可能耗上好几秒,放在服务器上很危险。
Q. 这里的式子可信吗?
每个式子都带着「必须匹配」和「必须不匹配」两组例子,测试会把 133 个全部真跑一遍。页面上看到的例子就是测试用的例子,所以说明和式子不可能各走各的。