ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

正则表达式实战指南:从语法基础到Java/PHP与爬虫应用

正则表达式实战指南:从语法基础到Java/PHP与爬虫应用 正则表达式这东西我刚入行那会儿觉得它就是个“玄学符号堆”后来被一个日志分析的活儿逼着啃了一个周末才真正尝到甜头。现在不管是写脚本过滤脏数据、抓网页提取关键字段还是做后端接口的参数校验我都会条件反射地先想想“能不能用正则解决”。它像一把瑞士军刀体积小但几乎每个项目里都有一两个场景非它不可。这篇就把我这些年用正则的经验、踩过的坑、以及从Java、PHP到爬虫场景下的实际用法通通理一遍希望能帮你少走点弯路。1. 正则表达式的核心思路与选型逻辑1.1 正则到底解决了什么“痛点”先说个最直观的例子给你一段用户提交的文本里面有手机号、邮箱、身份证号、订单号混在一起你需要把它们逐个挑出来并且校验格式是否正确。如果用字符串截取的办法得写一堆indexOf、substring遇到变长格式就崩。正则的做法是定义一套“模式”让引擎去文本里做模式匹配一条规则就能覆盖几百种情况。本质上正则是一种描述字符串形态的声明式语言。它不关心字符串的具体内容只关心结构的“形状”。比如\d{11}不用管数字是什么只要是11位数字就命中。这种“按形状匹配”的思路让它在文本处理领域几乎是唯一解。日常常见的场景包括校验类手机号、身份证、邮箱、URL、IP地址是否合法。提取类从HTML源码里抓链接、从日志里抽时间戳和错误码。替换类批量把文本中的日期格式从2023-10-01转成01/10/2023。切割类按分隔符拆分CSV行或者把长文本按标点切分。我在项目里很少写“一次性用完就丢”的正则更喜欢把常用的表达式沉淀成工具类或配置文件。后面你会看到正则的维护成本主要不在写而在理解所以规范命名和加注释比写出一个炫技的“一行流”重要得多。1.2 流派差异传统NFA与PCRE兼容性刚上手的时候很容易被不同语言的正则写法搞懵。Java正则、PHP正则、Python正则、JavaScript正则看着差不多实际细节差很多。这背后是正则引擎实现的历史问题绝大多数编程语言用的是传统型NFA非确定型有限自动机而grep、awk等命令行工具早期用的是POSIX标准的那套。这导致最典型的差异就是字符类、转义、命名分组和回溯行为的区别。例如\d在Java和PHP里默认表示[0-9]在Python里也是但如果你穿了re.ASCII标志就只匹配ASCII数字而JavaScript的\d始终是ASCII数字。再看命名分组Python写(?Pname...)Java写(?name...)PHP写(?Pname...)或者(?name...)都行。新手最容易踩的坑就是跨语言复制正则不调整语法结果运行时报错或者匹配结果完全不对。所以我的建议是先掌握元字符和逻辑组合的通用知识再针对你使用的语言查一遍该语言支持的“方言特性”。不要试图背住所有语言的写法但得知道去哪里查以及哪些特性是跨语言通用的比如.*?、[a-z]、^、$这些基本都一致。1.3 盲写 vs 可视化工具很多人一上来就打开IDE开始敲正则敲半天发现匹配不对然后又瞎加了一堆转义符号最后整个表达式变成一团乱麻。我现在的习惯是先在可视化工具里把正则“画”出来确认匹配逻辑无误再放进代码里。常用的工具有 regex101、regulex、regexper 这类能实时显示分组、量词作用范围有些还能分析回溯的步骤数。这类工具对新手特别友好因为你能直观看到(abc)和abc的区别到底在哪。不过要提醒一点可视化工具默认的语言引擎往往是PCRE或者JavaScript如果你最终要跑在Java或者PHP里最好切换一下右侧的“Flavor”选项或者至少记住它们的语法差异。否则在工具里测试通过复制到 IDE 里可能直接抛异常比如(?name...)在Python旧版本里不支持。2. 核心语法细节与实操要点2.1 元字符和量词的“语义边界”很多人用正则用了很久可能还是靠“试”而不是靠“懂”。我觉得最关键的点在于理解匹配的粒度。举个例子a匹配一个或多个a听上去很简单但a?是非贪婪匹配它尽可能少地匹配字符也就是只匹配一个a。这个差异在提取HTML标签的时候尤为重要。再比如[a-z]和[a-z]*的区别表示至少一次*表示零次也可以。用*的时候正则引擎实际上可以在任何位置匹配到一个“空字符串”这会导致split或replace时出现一些莫名其妙的结果。我遇到过有人用[0-9]*去校验字符串全是数字结果空字符串也能通过校验这就是没有分清“零次”和“至少一次”造成的。还有一个容易被忽视的是^和$的语义。在Java默认模式下^匹配整个字符串的开头$匹配整个字符串的结尾但在JavaScript里^和$在m标志多行模式下会变成匹配每一行的开头和结尾。如果不注意你拿Java的^\d{11}$去JS里配一个多行文本可能只校验了第一行或者碰巧匹配了中间某一行。所以能用matches()的就别用find()matches()要求整个字符串完全匹配find()只要找到子串就算成功语义差别极大。2.2 字符类的陷阱与转义规则字符类里的“减号”是另一个经典坑。写[a-z]没问题但如果你要匹配“a、-、z”这三个字符直接写[a-z]会被当成范围。正确做法是把减号放在字符类的最前面或最后面[-az]或者[az-]。同样^在字符类开头表示取反[^a-z]表示匹配任意非小写字母。如果想匹配字面意义的^需要写成[\^]或者把^放到非开头位置。转义要分两层看一层是正则语法本身的转义另一层是宿主语言字符串里的转义。在Java里写\d实际上字符串中要写成\\d因为Java字符串的反斜杠本身需要转义。在PHP单引号字符串里写\\d也会得到一个反斜杠加d很多时候你需要的反而是\\d传入正则函数时被解释为\d。就是这种“双重转义”让很多人抓狂。我的建议是遇到复杂的反斜杠组合时先在工具里调试通过再复制到代码里然后跑个最小测试用例确认。2.3 分组与反向引用的实战价值分组除了能提取片段还能用来做“前后一致”的匹配。比如要匹配“ABAB”这种重复形态的字符串可以用([A-Z])\1。\1表示引用第一个分组捕获的内容。这个特性在处理重复单词、成对标签时特别有用。HTML里匹配成对标签本质是捕获开标签的名称然后在闭标签处反向引用类似(/?)([a-zA-Z])再配合逻辑判断。当然真要解析HTML还是建议用专门的解析库正则只能处理结构规整、不嵌套的简单情况嵌套标签是正则的天然短板。非捕获分组(?:...)是我个人非常喜欢的一个符号。它表示把这一段内容当作整体参与量词或分支判断但不保存捕获内容。例如校验电话号码时(?:010|021)-?\d{8}把区号的选择作为一个整体而(?:)不产生额外分组编号后面对\1、\2的引用不会乱。这个习惯能避免“分组编号偏移”的坑。我见过有人写了一大串(\d{4})-(\d{2})-(\d{2})后面要扩展到支持YYYY/MM/DD直接在分支里加了(\d{4})/(\d{2})/(\d{2})结果分组编号全变了后面的引用全错。这时候把不需要的分组改成非捕获结构问题就没了。2.4 贪婪、懒惰与占有性能的胜负手正则性能卡顿通常不是匹配本身的问题而是回溯。经典例子是用(.*)*去匹配超长字符串这种“嵌套量词”在极端输入下会产生指数级的回溯路径甚至让CPU飙满。写过爬虫的人可能都经历过一条正则跑在几千行HTML上卡了好几秒。这里有几个经验能用字符类限定范围就不要用点号匹配万物。比如提取HTML标签属性值用[^]*就比.*安全得多它不会跨界匹配。能用非贪婪量词解决的问题不要用贪婪量词勉强凑。比如title(.*?)比title(.*)在多个title并存时更容易定位到最近的引号。能不用回溯就不回溯实在需要处理嵌套结构建议换状态机或者解析库。说得有点抽象给个具体案例我想从一段日志中提取“时间戳后面跟着的日志级别和消息”日志行长这样2025-05-01 12:00:01 ERROR 连接超时重试第3次我一开始写(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s(\w)\s(.*)看起来没问题。但如果日志里某些行中间有多余空格或者消息很短甚至消息为空(.*)就能匹配空字符串这没问题但引擎为了匹配“尽可能多”会先把整行吞掉再一点点“吐”出来找$。对于单行文本无所谓但如果把很多行合并成一个长字符串再用find()这个贪婪的.*就会吞掉后面十几行的内容。改成(.*?)后它会匹配到换行前为止取决于是否开启DOTALL行为立刻符合直觉了。3. 多语言与爬虫场景下的实战过程3.1 Java中的校验落地以身份证号为例Java正则用得最多的地方就是表单校验。身份证号这类文本如果只做基础格式校验其实很简单但很多人忽略了几点细节。我拿“Java 身份证号码如何用正则表达式校验”这个场景展开说说。身份证号码是18位前17位是数字最后一位可能是数字或X。最基础的正则^\d{17}[\dXx]$。这个能挡住“长度不对”“含字母且不是X”等明显错误但是挡不住“出生日期不可能”这类逻辑问题。比如999999199999999999这串也能匹配显然不是合法身份证。所以黑盒校验需要更细身份证的第7到14位是出生年月日并且要知道年月日是否真实存在。单靠正则做不到完整校验但可以用更精细的正则做前置过滤例如^\d{6}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$这个表达式把年份限制在18、19、20开头月份限制在01到12日期限制在01到31。它仍然无法校验2月30日但已经能过滤掉大量伪数据。真正严谨的校验必须配合代码逻辑通过LocalDate解析日期并抛出异常再计算校验位。正则在这里的作用是“快筛”把格式明显不对的请求直接挡在门外避免进入下游逻辑。Java代码里我会这样写private static final Pattern ID_CARD_PATTERN Pattern.compile(^\\d{6}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$); public boolean isIdCard(String idCard) { if (idCard null || !ID_CARD_PATTERN.matcher(idCard).matches()) { return false; } // 这里再做日期合法性和校验位计算 return validateBirthDate(idCard) validateCheckDigit(idCard); }注意我用的是matches()而不是find()。很多初学者直接Pattern.matches(regex, input)就是整串匹配也可以但如果你用matcher.find()会发现“包含18位身份证格式的任意文本”也能通过因为find()是“包含匹配”。Java的matches()必须全字符串匹配这点和JavaScript里的test()不同JavaScript的test()是“找子串”除非你用^和$把它夹住。所以跨语言移植时第一件事就是确认API的匹配语义。3.2 PHP中的捕获与替换从日志里筛数据PHP的正则主要用preg_match、preg_match_all、preg_replace。我最常干的一件事就是从乱七八糟的日志字符串里批量提取用户IP和访问路径。PHP的preg_match_all会把所有匹配结果塞进一个三维数组初看很反直觉但理解了PREG_PATTERN_ORDER和PREG_SET_ORDER之后就顺了。默认是前者意思是$matches[0]是所有完整匹配$matches[1]是所有第一个分组以此类推。如果你想要“每一条记录一个二维数组”这种结构就用PREG_SET_ORDER。举个例子日志里有这么几行192.168.1.10 - - [01/May/2025:12:00:01 0800] GET /api/users HTTP/1.1 200 1024 192.168.1.11 - - [01/May/2025:12:00:02 0800] POST /api/orders HTTP/1.1 500 512要提取IP、请求方法和路径可以这样写$pattern /^([\d.]) .*?\[(.*?)\] (\w) (\S?) HTTP\/[\d.] (\d{3})/m; preg_match_all($pattern, $logText, $matches, PREG_SET_ORDER); foreach ($matches as $m) { echo IP{$m[1]}, TIME{$m[2]}, METHOD{$m[3]}, PATH{$m[4]}, STATUS{$m[5]}\n; }这里有两个细节一是正则末尾加了m修饰符让^和$能匹配每一行的开头和结尾这样preg_match_all才能逐行命中二是(\S?)用来匹配路径避免路径中的空格或者后面HTTP版本号干扰。如果不加?贪婪模式下(\S)也能匹配到空格前为止因为\S本身就是非空白字符所以这里贪婪非贪婪其实都一样。真正的坑在于.*?匹配时间戳那一部分如果日志行里出现多个[贪婪版本会匹配到最靠后的一个]非贪婪则从前向后找效率也更高。PHP的正则函数返回false表示编译失败这在调试时很有用。一旦表达式里有不平衡的括号或者使用了当前PHP版本不支持的语法preg_match会直接返回false还给出一个preg_last_error()错误码。我遇到过在正则里用了(?name)但服务器PHP版本是5.2运行时直接报“unrecognized character after (?”换成(?Pname)才解决。这提醒我无论是Java还是PHP正则语法向后兼容性并不完美升级依赖时要回归测试正则相关的功能。3.3 爬虫里的正则实战从HTML中提取结构化数据爬虫场景下正则往往和requests、BeautifulSoup、lxml这些库混着用。很多爬虫教程一上来就说“用正则抓数据”但我的经验是能用XPath或CSS选择器不要用正则解析HTML。原因很简单HTML是嵌套结构正则不具备真正的“递归匹配”能力。HTML还可能出现在注释里、属性值里、JavaScript代码里用正则会误伤。比如你想提取所有div classtitle的内容一个不小心就把嵌套在内部的同名div也匹配进来。但是正则并不是不能用于爬虫它适合处理那些“HTML里夹杂的JSON数据”和“特定格式的字符串”。比如页面里有一段var userId 12345;的JS代码你不想引入一个完整的HTML解析器就写一个正则/var userId\s*\s*(\d)/i这种场景很常见。再比如从script标签里提取JSON字段因为页面可能是SSR渲染数据被塞进一个window.__INITIAL_STATE__ {...}变量里这时候用正则抓最外层的一对花括号再用json.loads去解析比硬用解析器更省事。注意花括号嵌套也会让正则陷入困境所以我一般先通过定位window.__INITIAL_STATE__找到等号位置然后用“括号计数”或者直接截取到;/script前面再交给JSON解析。正则只承担“定位锚点”的责任不承担“完整解析”的责任。我之前写过一个抓取商品列表的小爬虫页面中商品信息是以JSON-LD方式嵌入的结构比较规整。我的做法是先re.search(rscript typeapplication/ld\json(.*?)/script, html, re.S)把JSON-LD块整体提取出来再json.loads。这样即使里面有嵌套的}只要第一个匹配是非贪婪的(.*?)/script就能正确切到第一个闭标签。不要在这个场景里尝试写一个能匹配“任意平衡花括号”的正则那是在挑战正则引擎的边界没有意义。3.4 常用正则速查表与选型建议分享一批我项目里沉淀下来的常用正则几乎可以直接复制使用。用途正则说明手机号中国大陆^1[3-9]\d{9}$目前主流号段不含虚拟运营商邮箱^[\w.-][\w-](\.[\w-])$简版没有做域名合法性校验URL^https?://[\w.-](:\d)?(/[\w./?%-]*)?$够用但不要用于复杂URIIPv4^(?:(?:25[0-5]2[0-4]\d日期 YYYY-MM-DD^\d{4}-(0[1-9]1[0-2])-(0[1-9]时间戳 HH:mm:ss^([01]\d2[0-3]):[0-5]\d:[0-5]\d$用户名^[a-zA-Z][a-zA-Z0-9_]{2,15}$字母开头可含数字下划线长度3-16中文字符[\u4e00-\u9fa5]常用简版实际汉字区间更大整数或小数^-?\d(\.\d)?$支持负数和浮点这些不是“银弹”比如[\u4e00-\u9fa5]在Java和Python里写法相同但在PHP里要写成/[\x{4e00}-\x{9fa5}]/u因为PHP需要启用u修饰符才能正确处理Unicode。跨语言时这种差异最坑所以我在表格里标注的用途是“参考”真正落地前一定要在目标语言里跑一遍最小用例。选型上有几个原则校验场景用^...$锚定整个字符串提取场景不要用锚定并且要合理使用非贪婪量词替换场景注意区分替换全部还是替换第一个Java的replaceAll和replaceFirstPHP的preg_replace默认替换全部。如果你在做一个ETL流程数据量大但是结构固定可以优先考虑“正则先行过滤再交给结构化工具处理”的组合拳。4. 常见问题与排查技巧实录4.1 明明能匹配代码里却输出不了结果这是新手咨询量最高的问题。现象是你在regex101里用同样的表达式和测试字符串能高亮命中但放到Java/Python里却输出空。排查顺序一般是这样检查字符串是不是被转义坏了。Java里\d没写成\\d实际变成d的某种控制字节编译正则时不报错但匹配永远不命中。检查调用方法。find()和matches()不同test()和match()也不同先确认自己用的是“整串全匹配”还是“包含查找”。检查是否默认区分大小写。正则里[a-z]不会匹配A要么加i修饰符要么显式写成[a-zA-Z]。检查输入字符串里是否有不可见字符比如BOM头、全角空格、换行符。这在读文件场景下特别多。我实际遇到过从网页复制文本到程序里字符串里带了一个不换行空格\u00A0\s在某些语言的正则里默认不匹配这个字符导致边界匹配失败。解决方法是用\p{Zs}或者先做replaceAll(\\u00A0, )预处理。4.2 匹配结果比预期多或者少多匹配常见原因是贪婪量词范围过大。比如要从文本中提取所有书名号里的内容有人写《.*》如果一行里有多个书名号比如“《红楼梦》与《西游记》”这个正则可能从第一个《一直吞到最后一个》为止。应该写成《.*?》。少匹配常见原因是对字符类理解不完整。比如要匹配带小数点的数字只写了\d\.\d结果整数123没匹配上且123.这种畸形数字也匹配不上。如果你的需求是“能容忍缺省小数部分”就应该写成\d(\.\d)?。这本质上是用“可选分组”扩展表达能力。4.3 性能突然变慢回溯与灾难性回溯我印象最深的一次事故是处理一批用户昵称逻辑是“不允许出现连续重复字符”。我写了一个正则用来找连续重复的字母([a-zA-Z])\1。这个很快。但后来需求升级为“找出存在至少三个重复的子串”有人写了([a-zA-Z])\1\1结果在大文本上卡死了。这就是典型的灾难性回溯因为外层的[a-zA-Z]有无数种切分方式引擎需要穷举组合。排查时可以用超时控制来保护Java里可以设置Pattern.compile后由Matcher配合region限制搜索范围或者干脆在正则里加“原子组”(?...)来阻止回溯。PHP没有内置超时参数所以更要注意别写无界嵌套。我的建议是写正则时心里估算一下“分支和量词的笛卡尔积”。如果某个量词修饰的逻辑既能匹配长串又能匹配短串并且后面还有相邻的量词就要警惕回溯爆炸。能用字符类[^]*或者[0-9]之类限定字符集合的就不要用.。4.4 编码问题中文、Unicode与修饰符中文匹配的坑在PHP里非常典型。用/[\x{4e00}-\x{9fa5}]/必须加u修饰符写成/[\x{4e00}-\x{9fa5}]/u否则会报preg_match(): Compilation failed。原因是不加u时PHP按字节处理字符串而中文字节序列会被拆散。Java里没有这个问题因为Java的字符串本来就是UTF-16编码的char序列[\\u4e00-\\u9fa5]可以直接用。Python里如果字符串是str类型re模块默认按Unicode处理但没特殊需求建议写re.UNICODE或直接使用\w的unicode版本。还有一个容易被忽略的点正则里写\b单词边界时对中文支持并不友好。\b基于“字母数字”与“非字母数字”的边界判定在中文文本里每个汉字和空格之间也可能构成边界导致\b测试\b这类表达式产生反直觉的结果。如果要在中文文本中提取特定词不建议用\b包裹直接用查找即可。4.5 工具和调试经验我把自己的排错流程分享出来你可以参考写正则前先明确“匹配成功”的判定标准是“字符串里存在”还是“整个字符串完全匹配”。这会决定加不加^和$。在可视化工具中分段测试。把一个复杂正则拆成若干小块分别验证每个块的命中情况再拼接。这种“分而治之”的方法能迅速定位是哪个分支导致整体失败。用“最小失败用例”逐步加字符。比如匹配失败时先把字符串删到只留下一个能代表场景的关键字再逐步扩展开来观察哪一步开始失配。在代码里写好注释。我会在每个重要正则上方用注释写清楚它的输入样例、输出样例和兼容性说明。这样三个月后再看不至于靠猜。定期回归。正则和日期解析一样新的数据格式来了就可能失效。建议把典型的合法/非法数据做成单元测试每次调整表达式都跑一遍防止老功能被改坏。5. 进阶技巧从“会写”到“用得巧”5.1 把正则拆成可维护的“半成品”我见过有些代码里一条正则长达两百个字符全挤在一行虽然能跑但没有任何人愿意去改它。我的做法是用“字符串拼接”或者“注释分组”把正则拆成有名字的块。比如校验身份证号的正则我会这样组织地区码 \d{6} 出生日期 (18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01]) 顺序码 \d{3} 校验码 [\dXx] 整体 ^地区码出生日期顺序码校验码$在Java里我可以把不同的片段定义为静态常量再拼接到最终Pattern里。这样做的好处是将来出生日期的规则变了只需要调整对应的常量不用动整个表达式。还能在常量上加注释说明“这里为什么允许31日”。5.2 利用正则做“渐进式清洗”处理脏数据时正则经常被用来做“分层清洗”。我最近在处理一批用户地址文本里面混合了电话、邮箱、QQ号、微信号我的策略不是写一个超级正则去匹配所有内容而是写几个小正则按优先级依次提取并替换成占位符先提取并移除邮箱[a-zA-Z0-9_.-][a-zA-Z0-9-]\.[a-zA-Z0-9.]再提取并移除手机号1[3-9]\d{9}再提取纯数字的较长串\d{5,}剩下文本做分词或人工复核。这种渐进式清洗的好处是每一层独立可测清洗结果可追溯不会因为一条巨大正则在某一条数据上失效而全盘失败。这也是我在团队里比较推崇的做法正则是流水线上的刀具不是一次性的多功能瑞士军刀。5.3 正则与解析器配合的“最佳分工”HTML/XML/JSON这类结构化数据解析器是主场正则顶多当侦察兵。我做了这么多年爬虫经验很明确能用XPath、CSS选择器或json.loads解决的绝不用纯正则去啃。正则在爬虫里的高价值场景反而是“解析器不好处理的部分”比如从JS变量里提取数据、从内联样式中抽URL、从混乱的日志中切字段。举个例子一个网页里有很多链接如果只想抓取“以/item/开头且不以#结尾”的链接XPath可能要先过滤出所有a[href]再遍历判断。用正则直接扫描HTML文本也能做到但可能误伤JavaScript里的字符串。所以我会先用解析器拿到DOM树提取所有href属性值再对属性值列表逐个跑正则做规则判断。这样分工最干净。5.4 修正常见的“坏味道”写法写正则时间久了慢慢能看出一些“坏味道”遇到了我会主动修正用.*匹配任意字符但不考虑换行。这是最常见的坏味道。大多数语言默认.不匹配换行所以跨行文本会直接失配。改法是明确使用[\s\S]*或者re.DOTALL/(?s)修饰符并且使用非贪婪版本。用大量|连接静态字符串。比如(cat|dog|bird)这种写法没错但如果列表很长维护起来很痛苦。建议把分支列表放在代码里拼装模式字符串时用re.escape转义。过度使用(?:)来避免捕获。适度用非捕获分组没错但如果你发现一长串都是(?:...)考虑用字符类或者原子组替代。总是在正则里写死空格。输入数据的空白可能是不定长的使用\s比 更友好注意使用\s时可能匹配到换行如果不想匹配换行就改成[ \t]。6. 结尾我的一些个人体会正则这门手艺入门容易精通难但真正精通的标志不是能写出多复杂的表达式而是知道什么时候不用正则。我见过太多同学拿着正则去解析JSON、去匹配HTML嵌套标签最后搞出一堆补丁维护成本比用解析器高好几倍。反过来在一些数据清洗、格式校验、日志提取的小场景里正则又是性价比最高的工具短短一行就能省掉几十行字符串处理代码。我个人在实际操作中的一个习惯是每次写完一个比较复杂的正则都会在代码里放三组测试用例——一组是合法输入一组是非法输入一组是边界输入空字符串、超长字符串、含特殊字符的字符串。这让我在改需求时特别安心。还有一个小技巧如果你要匹配的字符串里包含/、#、~这类字符而你的语言支持自定义定界符比如PHP的#...#用定界符能省掉大量的转义。另外命名分组一定要用起来(?year\d{4})比(\d{4})在后续代码里清晰得多。最后再分享一个建议不要试图背正则而是要会查、会用工具、会拆解问题。网上那些“史上最全正则表达式合集”大部分你根本用不到真正需要的时候按场景搜索、测试、验证然后存进自己的工具库就好。希望这篇能帮你在正则这条路上少踩一些坑遇到文本处理任务时能有底气地说一句“这个我懂能用正则解决”。
返回列表