15

I want to use rx to create regular expressions with runtime values.

Currently, I'm doing this:

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

However, I'd rather avoid using eval. I've found rx-to-string, but it's not clear what FORM I should write:

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

How do I build an rx expression at runtime?

19

rx-to-string takes a regexp form as an argument. The syntax is the same as the argument of rx.

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

What you tried passing is not a regexp form, but a list of regexp forms. Since what you mean is the sequence of regular expressions symbol-start followed by one of a bunch of strings followed by symbol-end, you need to lead with the sequence operator sequence (which can be abbreviated to seq or :, or weirdly even and).

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

rx is in fact a tiny wrapper around rx-to-string that operates at compile time because it's a macro. What makes this confusing is that if you pass multiple arguments to rx, there is an implicit sequence operator. The documentation of rx could stand to be clarified.

(rx (: symbol-start (or "foo" "bar" "baz") symbol-end))
"\\_<\\(?:ba[rz]\\|foo\\)\\_>"
(rx symbol-start (or "foo" "bar" "baz") symbol-end)
"\\_<\\(?:ba[rz]\\|foo\\)\\_>"
  • 7
    "you pass multiple arguments to rx, there is an implicit sequence operator" -- aha! That's the main gotcha here. Thanks! – Wilfred Hughes Oct 17 '14 at 17:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.