Для этого вам нужно будет использовать правило followed-by
, в основном вы хотите многократно сопоставлять 'a' или 's', но без использования последнего токена. Вот код для этого:
(def a-or-s
(lit-alt-seq "as")) ;; same as (alt (lit \a) (lit \s))
(def ends-with-s
(conc
(rep* (conc a-or-s (followed-by a-or-s)))
(lit \s)))
Мы можем реорганизовать этот код для создания нежадной версии rep*
следующим образом:
(defn rep*? [subrule]
(rep* (conc subrule (followed-by subrule))))
Затем используйте его вместо rep*
, и ваш исходный код должен работать как положено. Хотя попробовав это ...
user> (rule-match (conc (rep*? a-or-s) (lit \s)) identity #(identity %2) {:remainder "aaaaaaaasss"})
([(\a \a) (\a \a) (\a \a) (\a \a) (\a \a) (\a \a) (\a \a) (\a \s) (\s \s) (\s \s)] \s)
... вы можете спросить «что происходит с выходом?», Ну rep*?
дает нам пары токенов, потому что это то, что мы просили. Это можно исправить, используя invisi-conc
вместо conc
:
(defn rep*? [subrule]
(rep* (invisi-conc subrule (followed-by subrule))))
user> (rule-match (conc (rep*? a-or-s) (lit \s)) identity #(identity %2) {:remainder "aaaaaaaasss"})
([\a \a \a \a \a \a \a \a \s \s] \s)