如何使 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)