emacs的正则表达式里, 有没有一个简单的方式可以表达一个symbol字符?

类似下面这个有没有更简单的写法:

"\\(\\sw\\|\\s_\\)\\{3,6\\}"

你实际的需求是什么?匹配 3 - 6 长度的符号么?如果是这样的话,一个比较简单写法是:

  • \_<.{3,6}\_>

但它不准确,会产生多余的匹配,比如下面会匹配到 foox y

(defun foo (x y z))

准确的写法大概就是你的写法,只是要还要限定 Symbol 的开头和结尾:

\_<\(?:\sw\|\s_\)\{3,6\}\_>
1 个赞

楼主是在找这种写法?

(rx (repeat 3 6 (or
                 (syntax word)   ;; => \\sw
                 (syntax symbol) ;; => \\s_
                 )))             ;; => \\(?:\\sw\\|\\s_\\)\\{3,6\\}

mei you

本来是想问一下有没有可以用单个元素表示一个symbol字符的, 这样不需要那么多括号, 方便后面跟{}, *, +等,类似\sw, 最近在定制go-mode的语法高亮, 感觉编程类mode里用symbol的频率非常高, 每次都要写那么长, 感觉很不方便

就是希望短一点, 或者类似[:symbol:]这种也可以, 好像是不支持.

rx这种方式挺直观啊.

`\\s_` 就是 symbol 了,从 rx 的写法能看出来。但是我不知道 `\\s_` 如何单独使用,好像都是要配合 `\\sw`。

再补充一点:\\{3,6\\} 可能不会按照你的预期工作,它能跳过长度小于 3 的符号,但是长度超过 6 的符号仍然会被匹配到。这时就要如 2#楼 所说,用 \\<_ ... \\_> 再包裹一层:

(let ((reg (rx symbol-start
               (repeat 3 6 (or (syntax word)
                               (syntax symbol)))
               symbol-end)))
  (list
   reg                              ;; => ("\\_<\\(?:\\sw\\|\\s_\\)\\{3,6\\}\\_>"
   (string-match-p reg "fo")        ;;     nil
   (string-match-p reg "foo")       ;;     0
   (string-match-p reg "foobar")    ;;     0
   (string-match-p reg "foobar ")   ;;     0
   (string-match-p reg "foobar1"))) ;;     nil)

没发现有现成的,不过可以试试自己添加个 Category,比如用 x 代表所有能组成 Symbol 的字符,然后就可以用 \cx 了。

(info "(elisp) Regexp Backslash") (注意最后一句话)

‘\cC’
     matches any character whose category is C.  Here C is a character
     that represents a category: thus, ‘c’ for Chinese characters or ‘g’
     for Greek characters in the standard category table.  You can see
     the list of all the currently defined categories with ‘M-x
     describe-categories <RET>’.  You can also define your own
     categories in addition to the standard ones using the
     ‘define-category’ function (*note Categories::).
2 个赞

\s_表示连接符,比如c里面的下划线字符,\sw表示word,两者合起来组成symbol,所以两个经常写一起,比较长。

长度范围只是举个例子,个别情况下用到。

1 个赞

这个竟然也可以扩展

简单试了下确实可以扩展

(defvar chunyang-c-category-table
  (let ((table (make-category-table)))
    (define-category ?s "C identifiers characters" table)
    (dolist (char (seq-filter (lambda (char)
                                (string-match "[-_0-9A-Za-z]" (string char)))
                              (number-sequence 0 127)))
      (modify-category-entry char ?s table))
    table))

(set-category-table chunyang-c-category-table)

然后就能用 \cs 了,比如:

\_<\cs\{3,6\}\_>
1 个赞

好像是可以, 不过我把方括号里第一个减号去掉了不知道怎么实际还包括减号.

印象中在major-mode的实现文件里, \c正则好像比较少用, 一般都是用\s

“Categories” provide an alternate way of classifying characters syntactically.

看了一下文档里syntax table和catalog table的区别, 一个字符只能有一个syntax, 而可以属于多个catalog. 所以基于前者是没法实现symbol了, 一个字符要么是\sw要么是\s_. 后者理论上可以实现这种效果.

随便一提,如果要匹配一个完整的 Symbol,可以用 \_<.+?\_>,无需表达「一个 Symbol 字符」。

简单情况是可以, 但很多情况下不方便用, 比如c语言的符号不能数字开头

试图用正则表达式来准确无误地匹配 Symbol 即便假设有可能做到,也多半麻烦,更谈不上方便地直接输入了。