如何使 textX 语法识别普通字符串和特殊关键字
How to make a textX grammar recognize normal strings and special keywords
我觉得我错过了一些非常简单的东西。我正在尝试创建一个 textX 语法,使我的解析器能够识别普通文本标记与特殊关键字。在下面的语法中,我无法让 textX 识别由 SpecialKeyword
规则表示的 [LINK ...]
关键字,因为它被更通用的 NormalString
规则所吸收。
我得到的输入如下:
['\n', 'Text part before [LINK: REQ-001] Text part after.', '\n', 'Text part before [LINK: REQ-002] Text part after.', '\n']
虽然我希望它是:
['\n', 'Text part before ', My Link object with 'REQ-001', 'Text part after.', '\n', 'Text part before ', My Link object with 'REQ-002', 'Text part after.', '\n']
一个相关的问题是:如何使 NormalString
规则支持多行字符串?
from textx import metamodel_from_str
mm = metamodel_from_str('''
Text:
parts+=TextPart;
TextPart[noskipws]:
(NormalString | SpecialKeyword | '\n')
;
NormalString[noskipws]:
!SpecialKeyword /(.*)?/ // this is too greedy
;
SpecialKeyword[noskipws]:
Link // more keywords are coming later
;
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)
你很接近。解决方案是在 NormalString
中的每个否定断言之后匹配一个字符,然后重复。此外,通过 (?ms)
正则表达式参数实现多行匹配。
可以在 the textX docs 中阅读更多内容。
Link
规则很常见,这将导致 Python 对象,因此您需要提取实际关键字,该关键字应该是导致 Python 字符串的匹配规则。
这是完整的解决方案:
from textx import metamodel_from_str
mm = metamodel_from_str('''
Text:
parts+=TextPart;
TextPart[noskipws]:
Link | NormalString
;
NormalString[noskipws]:
(!SpecialKeyword /(?ms)./)*
;
SpecialKeyword:
LinkKW // more keywords are coming later
;
LinkKW: '[LINK: ';
Link[noskipws]:
LinkKW 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=True)
print(model.parts)
我觉得我错过了一些非常简单的东西。我正在尝试创建一个 textX 语法,使我的解析器能够识别普通文本标记与特殊关键字。在下面的语法中,我无法让 textX 识别由 SpecialKeyword
规则表示的 [LINK ...]
关键字,因为它被更通用的 NormalString
规则所吸收。
我得到的输入如下:
['\n', 'Text part before [LINK: REQ-001] Text part after.', '\n', 'Text part before [LINK: REQ-002] Text part after.', '\n']
虽然我希望它是:
['\n', 'Text part before ', My Link object with 'REQ-001', 'Text part after.', '\n', 'Text part before ', My Link object with 'REQ-002', 'Text part after.', '\n']
一个相关的问题是:如何使 NormalString
规则支持多行字符串?
from textx import metamodel_from_str
mm = metamodel_from_str('''
Text:
parts+=TextPart;
TextPart[noskipws]:
(NormalString | SpecialKeyword | '\n')
;
NormalString[noskipws]:
!SpecialKeyword /(.*)?/ // this is too greedy
;
SpecialKeyword[noskipws]:
Link // more keywords are coming later
;
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)
你很接近。解决方案是在 NormalString
中的每个否定断言之后匹配一个字符,然后重复。此外,通过 (?ms)
正则表达式参数实现多行匹配。
可以在 the textX docs 中阅读更多内容。
Link
规则很常见,这将导致 Python 对象,因此您需要提取实际关键字,该关键字应该是导致 Python 字符串的匹配规则。
这是完整的解决方案:
from textx import metamodel_from_str
mm = metamodel_from_str('''
Text:
parts+=TextPart;
TextPart[noskipws]:
Link | NormalString
;
NormalString[noskipws]:
(!SpecialKeyword /(?ms)./)*
;
SpecialKeyword:
LinkKW // more keywords are coming later
;
LinkKW: '[LINK: ';
Link[noskipws]:
LinkKW 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=True)
print(model.parts)