Как правильно смешивать 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.