我想使用textx来解析"foo bar.""foo bar ."不同(如果没有空格,则将'.'绑定到最后一个单词,但仍单独解析'.')。

我本以为以下可以做到这一点:

from textx.metamodel import metamodel_from_str

mm = metamodel_from_str('''
Sentence[skipws]: words*=Word;
Word[noskipws]: ID '.' | ID | '.';
''')


但是它将以下内容解析为两个而不是三个“单词”:

>>> print(len(mm.model_from_str('''foo bar .''').words))
2


如果我改为这样做,它似乎可以正常工作:

from textx.metamodel import metamodel_from_str

mm = metamodel_from_str('''
Sentence[skipws]: (words=Word /(?i) */)*;
Word[noskipws]: ID '.' | ID | '.';
''', skipws=False)


我不清楚,为什么在这里需要skipps = False,还是手动正则表达式...,如果我不使用(?i),它将引发异常(“无可重复”)。

最佳答案

skipws/noskipws applies immediately,因此,Word规则的第一个匹配项将在ID之前看到前面的空格,因此ID '.'将永远不会匹配。您必须占用这些空间。这是完成的方式:

mm = metamodel_from_str('''
Sentence[skipws]: words*=Word;
Word[noskipws]: /\s*/- (ID '.' | ID | '.');
''')

print(mm.model_from_str('foo bar.', debug=True).words)



-之后的/\s*/运算符是match suppression,这意味着我们不希望匹配的那一部分出现在我们的Word中。最好使用debug=True进行分析,以了解幕后发生的事情。

更新2019-10-02:OrderedChoice中存在一个错误,该错误使skipws在替代选择的情况下的工作方式引起混乱。从1.9.1版开始,它已在Arpeggio解析器中修复。

07-28 05:17