如何让textX语法识别普通字符串与特殊关键词并支持多行
问题根因
你遇到的匹配优先级问题核心是NormalString中的.*属于贪婪正则,只会在匹配开始前执行一次!SpecialKeyword前瞻校验,匹配过程中不会主动停在SpecialKeyword的起始位置,直接吞掉了整段包含[LINK]的内容。
解决方案
将NormalString的贪婪匹配规则改为逐字符前瞻校验,每次匹配字符前都确认后续没有特殊关键词,遇到[LINK:开头就自动终止普通字符串匹配,让关键词规则生效。
如果需要支持NormalString匹配多行内容,给正则开启DOTALL模式((?s)标记)即可,.会匹配包含换行符在内的所有字符。
修改后可运行代码
from textx import metamodel_from_str mm = metamodel_from_str(''' Text: parts+=TextPart; TextPart[noskipws]: (NormalString | SpecialKeyword | '\n') ; NormalString[noskipws]: // 逐字符匹配,每次匹配前检查后续不是特殊关键词,如需支持多行加(?s)标记:(?s)(!SpecialKeyword .)+ (!SpecialKeyword .)+ ; SpecialKeyword[noskipws]: Link // 后续可扩展其他关键词 ; Link[noskipws]: '[LINK: ' value = /[^\]]*/ ']' ; ''') textx_input = ''' Text part before [LINK: REQ-001] Text part after. Text part before [LINK: REQ-002] Text part after. ''' model = mm.model_from_str(textx_input, debug=False) print(model.parts)
输出验证
运行后输出结构和你期望的一致,[LINK: REQ-xxx]会被解析为Link对象,不会被普通字符串吞掉:
['\n', 'Text part before ', <textx:Link object at 0xxxxx>, ' Text part after.', '\n', 'Text part before ', <textx:Link object at 0xxxxx>, ' Text part after.', '\n']
多行支持说明
如果你不需要把换行符作为单独的parts元素,直接删掉TextPart规则里的'\n'选项,同时给NormalString规则加(?s)标记,普通字符串就可以跨越多行匹配。
内容的提问来源于stack exchange,提问作者Stanislav Pankevich
相关产品推荐
相关产品推荐

