使用 rx 构建正则时如何让 `any` 匹配一个变量?

我在使用 rx 构建正则表达式的时候遇到了这样一个问题:

我需要匹配到一个字符串中的任意一个字符,但要求是这个字符串可以是自定义的,我定义了一个变量来表示这个字符串,但如果在 any 后直接跟这个变量的话会报错

(setq t1 "abc")

(rx (any "abc"))
;; => "[a-c]"
(rx (any t1))
;; => rx--parse-any: Invalid rx ‘any’ argument: t1

;; 使用 literal/regexp 可以在运行 rx 时计算 lisp
;; 但会导致定义变量时必须以正则的形式来写
(rx (any (literal t1)))
;; => rx--parse-any: Invalid rx ‘any’ argument: (literal t1)
(rx (regexp t1))
;; => "abc"

;; 以正则的形式定义变量
(setq t2 "[abc]")
(rx (regexp t2))
;; => "[abc]"

想知道有没有办法是定义变量时就是单纯字符串,不用写正则的形式?

现在比较费劲的解决办法是

(rx (regexp (concat "[" t1 "]")))
;; => "[abc]"

不知道大家有没有更好的解决方法?

提供个思路

(setq t1 "abc")
(eval `(rx (any ,t1)))
;; => "[a-c]"
1 个赞

原来是用这种方式来解决的吗?太厉害了.jpg

这种方法比我硬 concat 的方法要好,生成出来的正则也更符合形式

更推荐使用 rx-to-string:

(let ((t1 "abc"))
  (rx-to-string `(any ,t1)))
;; => "[a-c]"
2 个赞

谢谢,不过我看了两个函数的文档,有两个问题想要请教下

  1. 之所以 rx 需要用 eval 才能取到变量的值,是因为 rx 是个宏,而 rx-to-string 是个函数的原因吗?

  2. 除了我这里遇到的问题,rxrx-to-string 还有什么使用上的不同吗?我看文档是 rx-to-stringliteralregexp 的要求必须是个常量,可以多添加一个参数来对匹配到的结果取消分组,还有别的需要注意的地方吗

rx 等于编译期运行 rx-to-string

啊这,又来了个我听不懂的编译期,我还是先学会 elisp 吧