在 Emacs 中,有如下几种文本替换的函数:
- •
replace-string
字面量替换 - • replace-regexp[1] 正则表达式替换
静态替换是最常见的,比如将 foobar
替换成 FOObar
,但是有的时候需要对匹配的文本进行一些处理, 这时就要用到函数调用了。 replace-regexp
就支持函数调用。
M-x replace-regexp RET regexp RET newstring RET
如果输入的 newstring
是以 ,
开头,那么后面就可以跟一个表达式,为了用上匹配的文本,有一些特殊字符:
- •
&
表示整个匹配的文本 - •
d
表示正则匹配的第 N 个分组
上面这两个特殊字符返回的类型是 string,如果匹配的文本是数字,那么可以用 #&
#d
表示。比如有如下文本:
123
456
789
执行 M-x replace-regexp RET [0-9]{3} RET ,( #& #&)
后,会得到:
246
912
1578
在写 Lisp 代码时, replace-regexp
对应的是
(while (re-search-forward REGEXP nil t)
(replace-match TO-STRING nil nil))
需要注意一点的时,在写 Lisp 代码时,转义字符需要有两个反斜线,比如 [0-9]\{3,\}
,这时因为:
反斜线不仅在 regexp 中是特殊字符,在 lisp 这门语言中,也是特殊字符。
比如,在 Lisp 中需要用 "\"
表示一个反斜线字面量,如果直接写 [0-9]{3,}
那么在经过 lisp 的 parser 后, 得到的是 [0-9]{3}
,而这个正则并不是说匹配一个数字三次,而只是一个数字,后面跟着 {3}
这三个字符而已。
这是在 Lisp 中写正则比较容易出错的一点,Manual 中的相关资料:
- • Syntax for Strings (GNU Emacs Lisp Reference Manual)[2]
- • Regexps (GNU Emacs Manual)[3]
- • Regexp Backslash (GNU Emacs Manual)[4]
最后,比如有如下文本,需要把其中的 unix 时间戳替换为可读的时间,lisp 代码怎么写?
代码语言:javascript复制[
{
"value": 0.000521920668058455,
"timestamp": 1718598630000
},
{
"value": 0.0002609603340292275,
"timestamp": 1718598645000
},
{
"timestamp": 1718598675000
},
{
"timestamp": 1718598705000
},
{
"timestamp": 1718598720000
}
]
答案:
代码语言:javascript复制(defun ts->human-date ()
(interactive)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\b[0-9]\{13\}\b" nil t)
(replace-match (thread-last (/ (string-to-number (match-string 0))
1000)
(seconds-to-time)
(format-time-string "%Y-%m-%d %H:%M:%S %z"))))))
最终结果:
代码语言:javascript复制[
{
"value": 0.000521920668058455,
"timestamp": 2024-06-17 12:30:30 0800
},
{
"value": 0.0002609603340292275,
"timestamp": 2024-06-17 12:30:45 0800
},
{
"timestamp": 2024-06-17 12:31:15 0800
},
{
"timestamp": 2024-06-17 12:31:45 0800
},
{
"timestamp": 2024-06-17 12:32:00 0800
}
]
引用链接
[1]
replace-regexp: https://www.gnu.org/software/emacs/manual/html_node/emacs/Regexp-Replace.html
[2]
Syntax for Strings (GNU Emacs Lisp Reference Manual): https://www.gnu.org/software/emacs/manual/html_node/elisp/Syntax-for-Strings.html
[3]
Regexps (GNU Emacs Manual): https://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html
[4]
Regexp Backslash (GNU Emacs Manual): https://www.gnu.org/software/emacs/manual/html_node/emacs/Regexp-Backslash.html