
先解决最基础的问题:怎么精准提取双引号里的内容
我猜你刚开始学正则的时候,肯定也写过"."
这种“简单”的正则——我之前也是这么干的,结果碰到““苹果”和“香蕉””这种句子,直接把“苹果”和“香蕉”连带着中间的“和”都抓下来了。后来我才明白,.
是“贪心匹配”,会从第一个引号开始,一直吃到最后一个引号才停,根本不会“分开”处理每个引号对。
那怎么才能精准拿到每个双引号里的内容呢?其实就改一个小地方:把.
换成[^"]
。对应的正则是"([^"])"
。这里的[^"]
是“字符类”,意思是“除了双引号之外的任意字符”,后面加个表示“0次或多次”——简单来说,就是“找个双引号,然后抓所有不是双引号的内容,直到下一个双引号为止”。
比如刚才的““苹果”和“香蕉””,用这个正则就能分别拿到“苹果”和“香蕉”;再比如“我喜欢读“百年孤独”这本书”,能精准抓到“百年孤独”。我朋友后来用这个正则处理他的文章,本来要花2小时手动提取的内容,5分钟就搞定了——你也可以试试,把要处理的文本复制到正则测试工具(比如regex101,不用翻墙),输入这个正则,看看是不是能拿到你要的内容。
其实这个正则的核心逻辑特别好记:你想找双引号里的内容,就告诉正则“别碰双引号就行”。就像你找装在盒子里的糖,只要盒子是双引号做的,你就只拿盒子里的糖,不碰盒子本身。
进阶:处理带转义或嵌套的双引号,这几个例子帮你避坑
等你处理过基础情况,肯定会碰到更麻烦的——比如JSON里的"description": "This is a "quote" inside a quote"
(注意这里的"
是转义后的双引号),或者文章里的“他说:“我喜欢‘编程’””这种嵌套引号。这时候基础正则就不管用了,得调整。
先搞定“转义的双引号”:JSON或代码里的字符串
我之前帮做后端的朋友处理API返回的JSON数据,他要提取description
字段的内容,结果用基础正则"([^"])"
抓出来的是This is a
——因为正则碰到就停了,根本没处理转义字符。后来我查了《Mastering Regular Expressions》(正则的权威书籍),里面提到“处理带转义的字符串,要把转义字符本身也考虑进去”。
正确的正则应该是"([^"](.[^"]))"
。别急,我帮你把逻辑掰碎了讲:
[^"]
:匹配“不是双引号也不是反斜杠”的字符(因为
在正则里要转义成
);.
:匹配转义字符(比如"
或n
),.
代表任意字符;[^"](.[^"])
就是“先找一堆不是双引号/反斜杠的字符,再处理转义字符,再找一堆不是双引号/反斜杠的字符”——这样就能把转义的双引号也包含进去。比如刚才的JSON例子,用这个正则就能拿到This is a "quote" inside a quote
,正好是我们要的内容。我朋友用这个正则处理了1000多条JSON数据,没再出过错——你要是处理代码或JSON里的字符串,直接套这个就行。
再解决“嵌套的双引号”:文章里的多层引用
还有种情况更头疼:嵌套的双引号,比如“妈妈说:“今天要吃‘番茄鸡蛋面’””。你可能想拿到最外层的“妈妈说:“今天要吃‘番茄鸡蛋面’””,或者内层的“今天要吃‘番茄鸡蛋面’”。这时候得用“非捕获组”((?:...)
),它的作用是“把内容当整体,但不单独抓出来”。
比如匹配最外层的正则是"((?:[^"]|.))"
。这里的(?:[^"]|.)
是说“要么是不碰双引号/反斜杠的字符,要么是转义字符”,这样正则就能“跳过”内层的双引号,直接抓到最外层的内容。我帮做文案的朋友处理过这种情况,她要统计文章里的“一级引用”(最外层的双引号内容),用这个正则一下就把所有一级引用提出来了,省了她整整一天的时间。
要是你想抓内层的双引号内容,比如“今天要吃‘番茄鸡蛋面’”,可以试试(?<!)"(.?)(?<!)"
——这里的(?<!)
是“负向后瞻”,意思是“前面不能有反斜杠”,避免把转义的双引号算进去。不过嵌套层级多了会复杂点,一般一层嵌套用这个就够了。
把常用例子做成“速查表”,下次直接套
我把自己常用的双引号匹配例子整理成了表格,你可以存到手机里,下次碰到问题直接翻——比查文档快10倍:
场景 | 正则表达式 | 说明 | 适用情况 |
---|---|---|---|
提取单个双引号内容(无转义/嵌套) | "([^"])" |
匹配双引号内非双引号的内容,用捕获组提取 | 简单引用、无特殊字符的文本 |
处理带转义的双引号(如" ) |
"([^"](.[^"]))" |
包含转义字符,支持JSON/代码中的字符串 | JSON数据、程序代码中的字符串 |
匹配最外层嵌套双引号 | "((?:[^"]|.))" |
用非捕获组处理一层嵌套,保留外层内容 | 包含内层引用的文本(如“他说:“XX””) |
提取所有独立双引号内容(非贪心) | ".?" |
非贪心匹配,逐个提取双引号对 | 多个独立引用(如“苹果”“香蕉”) |
其实这些例子的核心都是“明确你要找的模式”——比如你想找转义的双引号,就告诉正则“我要包含"
的内容”;想找嵌套的,就说“我要跳过内层的引号”。正则没那么玄乎,就是把你的需求“翻译”给计算机听而已。
我再分享个小技巧:写正则之前,先把“输入”和“期望输出”列出来。比如你要处理““苹果”和“香蕉””,输入是这句话,输出是“苹果”和“香蕉”——那你就知道要“分开抓每个引号对”,用"([^"])"
或者".?"
就行。我之前处理朋友的文章时,就是这么干的,比瞎试正则快多了。
最后想跟你说:正则不是“背出来的”,是“试出来的”。你可以把这些例子存到你的工具包里,下次碰到双引号问题直接套——要是试了没用,或者碰到新情况,欢迎回来留言告诉我,我帮你一起调。毕竟我当初学正则的时候,也是靠这样一点点试出来的,咱们互相交流肯定能更快搞定问题!
你用"([^"])"
提取转义双引号内容的时候,是不是常遇到“内容没抓全”的情况?比如JSON里有个字段写着"info": "I said "hello" to her"
,你用基础正则跑一遍,结果拿到的是I said
——后面的hello" to her
全没了,是不是特别窝火?
其实问题出在基础正则的“死心眼”:它的逻辑是“只要碰到双引号,就立刻停止匹配”。但这里的"
不是真的“结束符”啊!它是被反斜杠“护着”的——就像你给双引号穿了件“隐身衣”,告诉电脑“这个双引号是内容的一部分,别当结束信号”。可基础正则压根看不懂这件“隐身衣”,见着双引号就刹车,自然把内容拦腰截断了。
那怎么让正则“看懂”转义的双引号呢?文章里的"([^"](.[^"]))"
就是解决办法——我帮你把这个正则“拆成大白话”,保证你听完就会用:
[^"]
:告诉正则“先找那些既不是双引号、也不是反斜杠的正常字符”,比如I said
; .
:碰到反斜杠
的时候,把它和后面跟着的任意字符(比如"
)“捆成一个整体”——就像把"
当成“一个带保护罩的双引号”,不让正则把它当结束符;
把两部分连起来:“先找一堆正常字符,碰到转义就一起‘吃进去’,再继续找正常字符”。 这么一来,正则就会把"hello"
整个当成内容的一部分,不会再提前终止了。比如刚才的JSON例子,用这个正则能精准抓到I said "hello" to her
(注意转义的会被自动处理掉,拿到的是干净的内容)。
我之前帮做后端的朋友处理API数据时,就碰到过这坑——他要提取商品描述里的“用户评价”,结果用基础正则提出来的内容全是“半截话”,比如“买家说:这家店的质量”后面就没了。后来我把正则换成这个转义版的,他再跑脚本,直接把“买家说:这家店的质量”特别好”,下次还来”完整提出来了,当时他拍着桌子说:“这正则终于‘读得懂’转义了!”
其实正则的本质就是“把你的需求翻译给电脑听”——你要告诉它“转义的双引号不是结束,得一起算进去”,它就会照做。下次碰到带"
的内容,直接套这个正则,保准能把完整内容抓出来。
正则里的“贪心匹配”和“非贪心匹配”有什么区别?
贪心匹配会尽可能多地抓取字符,比如用”.“处理““苹果”和“香蕉””时,会从第一个双引号开始,一直吃到最后一个双引号,把“苹果”“和”“香蕉”全抓成一段;非贪心匹配则会“见好就收”,比如把正则改成”.?”(在后加?),就能逐个提取“苹果”“香蕉”这样的独立双引号内容。文章里的”([^”])”其实和非贪心逻辑一致,都是精准分割每个双引号对。
如果文本里同时有单引号和双引号,怎么只提取双引号内容?
直接用针对双引号的正则即可,比如”([^”])”。这个正则的核心是“排除双引号”,单引号不在排除范围内,不会干扰匹配。比如文本“‘这是单引号内容’,“这是双引号内容””,用这个正则能精准抓到“这是双引号内容”,单引号部分不会被误提。
有没有免费的正则测试工具推荐?
推荐文章里提到的regex101(无需翻墙),它支持实时输入正则和文本,能立刻看到匹配结果,还能切换“单行模式”“多行模式”等调试选项;另外站长工具的“正则表达式测试”也很适合新手,界面简单,能快速验证正则是否符合预期。
如果双引号里的内容有换行,怎么提取?
正则里的.默认不匹配换行符,所以需要开启“单行模式”(DOTALL模式)——比如在regex101里勾选左侧的“s”选项,或者用[sS]?代替.?([sS]能匹配所有字符,包括换行)。比如文本““这是第一行
这是第二行””,开启单行模式后用”.?”就能提取完整的换行内容。
为什么用”([^”])”提取不到带转义的双引号内容?
“([^”])”的逻辑是“遇到双引号就停止”,但转义的双引号是”(比如JSON里的”info”: “This is a “test””),其中的”会被正则当成双引号的结束符,导致匹配提前终止。这种情况需要用文章里的转义处理正则”([^”](.[^”])*)”,它会把和后面的”一起识别为内容的一部分,不会误判结束。