Как правильно смешивать textx skipws/non-skipws?

Я хочу использовать 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)

Мне непонятно, почему здесь необходим skipws=False или ручное регулярное выражение... и если я оставлю (?i) он генерирует исключение ("нечего повторять").

1 ответ

skipws/noskipws применяется немедленно, таким образом, первое совпадение вашего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*/это подавление совпадений, то есть мы не хотим, чтобы эта часть совпадения попала в нашWord. Всегда полезно запускать парсинг сdebug=True чтобы увидеть, что происходит за кулисами.

Обновление 2019-10-02: вOrderedChoice это внесло путаницу в путь skipwsработал в контексте альтернативного выбора. Это было исправлено в парсере арпеджио начиная с версии 1.9.1.

Другие вопросы по тегам