Regex重复分组捕获问题:如何正确提取目标词汇分组
正则匹配与分组问题解决方案
嘿,我来帮你搞定这个正则的问题!先理清楚你的需求和当前遇到的卡点:
需求与示例
待处理的有效文本
- Example 1:
'lun et mer et mar' - Example 2:
'lun. et mer. - mar.' - Example 3:
'lun a ven'
必须排除的无效文本(完全不能匹配)
- Negative example 4:
'sept à juin' - Negative example 5:
'foo bar' - Negative example 6:
'9h30 - 18h'
预期的分组结果
- Example 1:
['lun', 'et', 'mer', 'et', 'mar'] - Example 2:
['lun', 'et', 'mer', '-', 'mar'] - Example 3:
['lun', 'a', 'ven']
当前遇到的问题
你尝试的正则是:
(?:((lun|mar|mer)\.?\s*(\-|au|a|à|et)?\s*)+)
但结果只捕获到最后一个词汇mar两次。你已经意识到这是重复捕获组的问题,但调整后还是没解决,对吧?
重要提示:必须用正则完成,因为需要通过完全匹配判断数据类型,像'sept à juin'这类内容必须被完全排除。
问题根源与解决方案
你的判断没错——问题出在重复捕获组的特性:当捕获组被+或*重复调用时,正则引擎只会保留该组最后一次匹配的内容,所以之前的写法只能拿到最后一个匹配项。
我们可以拆分思路,分两步解决:先验证整个文本是否合法,再提取所有有效元素。
1. 验证文本合法性(完全匹配)
首先写一个正则,确保整个文本只由合法元素(目标词汇+连接词)和空格组成:
^(?:\s*(?:(?:lun|mar|mer)\.?|et|a|à|-)\s*)+$
^和$确保从文本开头到结尾完全匹配(?:lun|mar|mer)\.?匹配目标词汇,允许末尾带.et|a|à|-匹配合法的连接词- 整个结构允许元素之间有任意数量的空格
用这个正则测试,就能排除所有无效文本(比如'sept à juin'这类完全不符合的)。
2. 提取所有有效元素
当文本通过合法性验证后,用全局匹配提取所有元素,再去掉末尾的.:
(?:lun|mar|mer)\.?|et|a|à|-
加上g标志全局匹配,然后对每个结果做个小处理:把.去掉(比如lun.转成lun)。
完整示例(以JavaScript为例)
拿Example 2的文本测试:
const text = 'lun. et mer. - mar.'; // 验证合法性的正则 const validateRegex = /^(?:\s*(?:(?:lun|mar|mer)\.?|et|a|à|-)\s*)+$/; // 提取元素的正则 const extractRegex = /(?:lun|mar|mer)\.?|et|a|à|-/g; if (validateRegex.test(text)) { const result = text.match(extractRegex).map(item => item.replace(/\.$/, '')); console.log(result); // 输出 ["lun", "et", "mer", "-", "mar"] } else { console.log('这个文本不符合要求哦'); }
为什么之前的写法不行?
你之前的正则把词汇和连接词打包进了一个重复的捕获组,每次循环都会覆盖捕获组的内容,最后只留下最后一次匹配的结果。拆分后分别匹配单个元素,再全局提取,就能拿到所有符合要求的项了。
内容的提问来源于stack exchange,提问作者Nikola Zarić
相关产品推荐
相关产品推荐

