正则表达式实用指南:从零到一的上手攻略

解密正则表达式:程序员的文本匹配利器

如果你和曾经的我一样,每次看到正则表达式都头皮发麻,那这篇文章就是为你准备的。

别怕,正则表达式没那么玄乎。说白了,它就是一种超强的文本“查找与替换”工具。小到检查用户输入的邮箱格式是否正确,大到从上万行日志里捞出你想要的那条信息,都离不开它。它就是程序员处理文本的瑞士军刀。

这篇指南不会讲得天花乱坠,只讲最常用、最核心的那些部分,保证你能快速上手,解决掉80%的日常问题。


热身运动:找个好用的“游乐场”

在正式开干前,你需要一个能随时测试你想法的地方。别总是在IDE或代码里print调试,效率太低。

强烈推荐 **regex101.com**。

这网站好在哪?它不光能告诉你匹配对了没,还会在右边把你的表达式拆开来,告诉你每一步都是什么意思。对于新手来说,这简直是神仙功能。后面我们的所有例子,你都可以直接复制进去自己试试看。


核心招式:基础语法

掌握下面这几招,你就已经入门了。

1. 限定符:控制出现的次数

这是正则表达式最基本的功能。

  • ? 问号:代表“可有可无”,也就是出现0次或1次。比如colors?可以同时匹配colorcolors
  • * 星号:代表“随便来”,出现0次、1次或很多次都行。比如ab*c可以匹配acabcabbbbc
  • + 加号:和星号很像,但代表“至少要有一个”,也就是出现1次或很多次。ab+c就没法匹配ac了。
  • {} 花括号:让你精确控制次数。
    • a{3}:不多不少,必须是3个a。
    • a{2,5}:最少2个,最多5个a。
    • a{2,}:最少2个,上不封顶。

2. 分组与分支:处理组合与多选

  • () 括号:把一堆东西包起来,当成一个整体。比如你想匹配好几个连续的ab,就要用(ab)+,这样+才会作用于整个ab
  • | 竖线:代表“或者”。I love (cats|dogs)就能匹配I love catsI love dogs。注意括号是必须的,不然就变成I love cats或者dogs了,意思全变了。

3. 字符类:指定一个范围

[]方括号允许你自定义一个“字符集合”,只要字符属于这个集合,就能匹配。

  • [abc]:匹配 a、b、c 中的任意一个。
  • [a-z]:匹配所有小写字母。
  • [a-zA-Z0-9]:匹配所有字母和数字。
  • [^0-9]:开头的^表示“取反”,所以这个是匹配所有数字的字符。

4. 元字符:常用的“简写”

正则表达式的设计者早就为我们准备好了一些常用的字符类简写,省得我们每次都写方括号。

  • \d:任意数字,相当于[0-9]
  • \w:任意“单词”字符,包括字母、数字和下划线,相当于[a-zA-Z0-9_]
  • \s:任意空白,包括空格、Tab、换行符。
  • . (英文句点):这是个大杀器,能匹配除了换行符之外的任何单个字符。
  • \D, \W, \S:用大写字母表示对应小写版本的“取反”。比如\D就是匹配任意非数字字符。

5. 定位符:锚定位置

这些符号不匹配任何字符,而是匹配一个“位置”。

  • ^:锚定一行的开始。^Hello只会匹配以Hello开头的行。
  • $:锚定一行的结束。world$只会匹配以world结尾的行。
  • \b:锚定一个单词的边界。用\bcat\b就能只匹配单词cat,而不会匹配到concatenate里面的cat。

进阶心法:贪婪与懒惰

这是很多人刚开始会踩的坑。默认情况下,正则表达式是“贪婪”的。

什么意思?比如你有这么一段文本:

1
<span><a>link</a></span>

你想用<.+>来匹配HTML标签。你以为它会匹配出<span><a></a></span>。但结果是,它会从第一个<一直匹配到最后一个>,把整个字符串全给你。

这就是“贪婪”,+*会尽可能多地吞掉字符。

解决方法很简单:在+*后面加个?,让它变得“懒惰”。

<.+?>,正则表达式就会在找到第一个匹配的>时立刻停下来。这在处理HTML、XML这类成对标签的文本时,几乎是必备技巧。


实战演练

理论讲完了,来点实际的。

场景一:提取十六进制颜色值

比如,从一堆CSS代码里找出所有像#ff6600这样的颜色值。

  1. 颜色以#开头。
  2. 后面跟着6个十六进制字符,也就是0-9a-f(大小写不限)。
  3. 我们希望它是个独立的单位,不希望匹配到#ff66000里面去。

组合起来就是:#([0-9a-fA-F]{6})\b

  • #匹配井号。
  • [0-9a-fA-F]定义了十六进制字符集。
  • {6}表示要6个。
  • \b定义了单词边界。

场景二:校验IP地址

这个需求很常见,但也更复杂。一个简单的\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}能匹配上格式,但它也会让999.999.999.999这样的鬼东西通过,因为IP地址每一段的范围是0-255。

要精确匹配,表达式会变得有点吓人。别怕,我们拆开看。

1
\b((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)\b

这个表达式的核心就是用|把0-255分成了几个区间来匹配:

  • 25[0-5]:匹配250-255
  • 2[0-4]\d:匹配200-249
  • 1\d{2}:匹配100-199
  • [1-9]?\d:匹配0-99

然后用分组和{3}把它重复三次,再跟上最后一段。这个例子有点劝退,看不懂没关系,先理解思路,需要用的时候再回来查就行。


总结与展望

到这里,你已经掌握了正则表达式的绝大部分精华。下面这张表可以当做你的备忘录。

类型语法描述
限定符*, +, ?, {}控制数量
分支(a|b)A或B
字符类[...], [^...]集合与排除
元字符\d, \w, \s, .常用简写
定位符^, $, \b匹配位置
模式+, * (贪婪) vs +?, *? (懒惰)匹配策略

正则表达式能做的远不止这些,还有捕获组、反向引用、零宽断言等更高级的玩法,那些可以让你写出更精妙、更高效的表达式。不过饭要一口一口吃,先把今天学的这些在实际项目中用起来,你会发现处理字符串的效率大大提升。如果感兴趣的话后续可能会在出几篇相关的博客。

如果你想继续深入,下面这几个资源质量非常高:

去动手试试吧,这才是掌握一门技术的最好方式。