Jak utworzyć dynamiczne wyrażenie regularne za pomocą rx?

15

Chcę używać rxdo tworzenia wyrażeń regularnych z wartościami środowiska wykonawczego.

Obecnie robię to:

(setq strings '("foo" "bar" "baz"))
(eval `(rx symbol-start (or ,@strings) symbol-end))

Wolałbym jednak unikać używania eval. Znalazłem rx-to-string, ale nie jest jasne, jaki FORMULARZ powinienem napisać:

;; error: Unknown rx form `symbol-start
(rx-to-string '(symbol-start (or ,@strings) symbol-end))

Jak zbudować rxwyrażenie w czasie wykonywania?

Wilfred Hughes
źródło

Odpowiedzi:

18

rx-to-stringprzyjmuje formę wyrażenia regularnego jako argument. Składnia jest taka sama jak argument rx.

(rx-to-string '(or "foo" "bar"))
"\\(?:\\(?:bar\\|foo\\)\\)"

To, co próbowałeś przekazać, to nie forma wyrażenia regularnego, ale lista formularzy wyrażeń regularnych. Ponieważ to, co masz na myśli jest ciągiem wyrażeń regularnych symbol-startnastępnie jeden pęczek ciągów następnie symbol-end, trzeba prowadzić z operatorem sekwencji sequence(które można w skrócie seqlub :, lub nawet dziwnie and).

(rx-to-string `(: symbol-start (or ,@strings) symbol-end))
"\\(?:\\_<\\(?:ba[rz]\\|foo\\)\\_>\\)"

rxto tak naprawdę małe opakowanie, rx-to-stringktóre działa w czasie kompilacji, ponieważ jest makrem. Co sprawia, że ​​to mylące jest to, że jeśli przekazujesz wiele argumentów rx, istnieje domyślny sequenceoperator. Dokumentacja rxmoże być wyjaśniona.

(rx (: symbol-start (or "foo" "bar" "baz") symbol-end))
"\\_<\\(?:ba[rz]\\|foo\\)\\_>"
(rx symbol-start (or "foo" "bar" "baz") symbol-end)
"\\_<\\(?:ba[rz]\\|foo\\)\\_>"
Gilles „SO- przestań być zły”
źródło
8
„przekazujesz wiele argumentów do rx, istnieje domyślny operator sekwencji” - aha! To główna gotcha tutaj. Dzięki!
Wilfred Hughes