JFlex正则嵌套负向预查实现:避免数字匹配连续点运算符
在JFlex中实现Wolfram语言数字的负向预查(避免误匹配
..运算符) 问题描述
我正在为Wolfram语言开发词法分析器,碰到了一个棘手的匹配问题:
- 单独的
1是合法数字 - 但
1..需要被拆分为数字1和运算符..,而不是把1.当成数字、剩下的.当成其他符号
Wolfram的数字定义本身就很复杂,我原本打算在嵌套的正则结构里用(?!...)负向预查,确保数字结尾的.后面不会紧跟着另一个.,但JFlex只支持在规则层面使用负向预查,没法直接在正则内部嵌套使用。下面是我当前的数字规则代码:
Digits = [0-9]+ Digits2 = [0-9a-zA-Z]+ Base = 2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36 Number = {Digits}((\.){Digits}?)? | \.{Digits} PrecisionNumber = {Number}`((`?){Number})? BaseNumber = {Base} "^^" {Digits2}(\.{Digits2}?)? BasePrecisionNumber = {BaseNumber}((`{Number}?)|(``{Number})) ScientificInteger = {Number} "\*^"(-?){Digits} ScientificNumber = {PrecisionNumber} "\*^"(-?){Digits} BaseScientificNumber = {BasePrecisionNumber} "\*^"(-?){Digits} {BaseScientificNumber}| {BasePrecisionNumber}| {ScientificInteger}| {BaseNumber}| {ScientificNumber}| {PrecisionNumber}| {Number} { return WLElementTypes.NUMBER; }
解决方案:结合JFlex规则优先级与规则层面负向预查
JFlex的匹配逻辑是从上到下优先匹配最长/最早的规则,而且支持在规则的模式末尾添加负向前瞻断言,我们可以利用这两个特性解决问题:
1. 优先定义..运算符规则
把..的匹配规则放在所有数字规则的最前面,这样JFlex会优先识别连续两个点为运算符,而不会把它们拆成数字的一部分+单个点:
// 放在所有数字规则之前 .. { return WLElementTypes.DOT_DOT_OPERATOR; }
2. 修改数字规则,添加规则层面的负向预查
我们需要给所有数字相关的正则添加(?!\.)负向前瞻,确保当数字以.结尾时,后面不会紧跟着另一个.。修改后的规则如下:
Digits = [0-9]+ Digits2 = [0-9a-zA-Z]+ Base = 2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36 // 修改Number规则:确保结尾的.后面不是. Number = {Digits}(\.{Digits}?)?(?!\.) | \.{Digits}(?!\.) // 拆分解释: // - {Digits}(\.{Digits}?)?(?!\.):匹配整数或带小数的数字,结尾如果是.则后面不能跟. // - \.{Digits}(?!\.):匹配以.开头的小数(如.123),确保后面没有多余的. PrecisionNumber = {Number}((`?){Number})?(?!\.) BaseNumber = {Base} "^^" {Digits2}(\.{Digits2}?)?(?!\.) BasePrecisionNumber = {BaseNumber}((`{Number}?)|(``{Number}))(?!\.) ScientificInteger = {Number} "\*^"(-?){Digits}(?!\.) ScientificNumber = {PrecisionNumber} "\*^"(-?){Digits}(?!\.) BaseScientificNumber = {BasePrecisionNumber} "\*^"(-?){Digits}(?!\.) // 最终数字匹配规则 {BaseScientificNumber}|{BasePrecisionNumber}|{ScientificInteger}|{BaseNumber}|{ScientificNumber}|{PrecisionNumber}|{Number} { return WLElementTypes.NUMBER; }
3. 验证匹配效果
修改后可以正确处理这些场景:
1→ 匹配为数字1..→ 先匹配1(数字),再匹配..(运算符)1.2→ 匹配为合法的浮点数字1.→ 匹配为合法的浮点数字(Wolfram允许这种写法)10^^a.b→ 匹配为合法的基数数字
内容的提问来源于stack exchange,提问作者halirutan
相关产品推荐
相关产品推荐

