实际问题
不使用interactive function(M-%)如何批量替换文件中的字符串?应用场景为文字校验。
解决思路
字符串替换分三种情况:
- 在当前buffer替换
- 在指定文件中替换
- 为指定目录下所有文件替换。
用于替换的pair有两种来源:
repl-string-list
和repl-regexp-list
变量repl-file
对应的文件。
字符串查找的方式有两种,分别对应两个函数:
- 纯字符串
(replall-string)
- 正则表达式
(replall-regexp)
优先使用列表变量的值,如果该变量值为nil则使用repl-file对应的文件中的值。其中文件中的pair只能用于 replall-string
函数。两个变量列表的值分别对应两个函数。repl-file的格式为每行一个pair,分别为被替换的字符串和用于替换的字符串,用空格隔开。
代码实现
主函数 replall-string
和 replall-regexp
可以选择替换类型。对于具体的情况也可以直接使用具体的替换函数。代码如下:
(setq repl-string-list '(("old" "new") ("test" "测试") ("错误" "right") ("隔开你" "戈楷旎"))) (setq repl-regexp-list '(("\\." "。"))) (setq repl-file "~/replace.txt") (defun replall--read-pair-from-file () (let ((repl-list '())) (with-temp-buffer (insert-file-contents repl-file) (goto-char (point-min)) (while (< (point) (point-max)) (setq repl-pair (split-string (thing-at-point 'line) "[ \f\t\n\r\v]+" t "[ \f\t\n\r\v]+")) (if (null repl-pair) (next-line) (next-line) (setq repl-list (append repl-list (list repl-pair)))))) repl-list)) (defun replall--get-repl-string-list () (if (bound-and-true-p repl-string-list) repl-string-list (replall--read-pair-from-file))) (defun replall--get-repl-regexp-list () (if (bound-and-true-p repl-regexp-list) repl-regexp-list (message "please set variable 'repl-regexp-list'!"))) (defun replall--string (file lst) (with-temp-buffer (insert-file-contents file) (goto-char (point-min)) (dolist (pair lst) (while (search-forward (car pair) nil t) (replace-match (cadr pair))) (goto-char (point-min))) (write-file file))) (defun replall--regexp (file lst) (with-temp-buffer (insert-file-contents file) (goto-char (point-min)) (dolist (pair lst) (while (re-search-forward (car pair) nil t) (replace-match (cadr pair))) (goto-char (point-min))) (write-file file))) (defun replall-string-in-curr-buffer () (interactive) (let ((curr-file (buffer-file-name (current-buffer))) (repl-list (replall--get-repl-string-list))) (replall--string curr-file repl-list))) (defun replall-regexp-in-curr-buffer () (interactive) (let ((curr-file (buffer-file-name (current-buffer))) (repl-list (replall--get-repl-regexp-list))) (replall--regexp curr-file repl-list))) (defun replall-string-in-file (file repl) (interactive "fchoose a file to be processed: ") (let ((repl-list (replall--get-repl-string-list))) (replall--string file repl-list))) (defun replall-regexp-in-file (file repl) (interactive "fchoose a file to be processed: ") (let ((repl-list (replall--get-repl-regexp-list))) (replall--regexp file repl-list))) (defun replall--get-real-files-in-dir (dir) (let ((real-files) (files (directory-files dir))) (dolist (file files) (when (not (or (string= "." (substring file 0 1)) (string= "#" (substring file 0 1)) (string= "~" (substring file -1)))) (push file real-files))) real-files)) (defun replall-string-in-directory (dir) (interactive "Dchoose a directory to be processed: ") (let* ((repl-list (replall--get-repl-string-list)) (real-files (replall--get-real-files-in-dir dir))) (dolist (file real-files) (replall--string (concat dir file) repl-list)))) (defun replall-regexp-in-directory (dir) (interactive "Dchoose a directory to be processed: ") (let* ((repl-list (replall--get-repl-regexp-list)) (real-files (replall--get-real-files-in-dir dir))) (dolist (file real-files) (replall--regexp (concat dir file) repl-list)))) (defun replall-string (type) (interactive "sreplace string: 1.in current buffer 2.in a file 3.in a directory (input 1~3): ") (cond ((string= type "1") (replall-string-in-curr-buffer)) ((string= type "2") (call-interactively #'replall-string-in-file)) ((string= type "3") (call-interactively #'replall-string-in-directory)) (t (message "please input 1~3!")))) (defun replall-regexp (type) (interactive "sreplace regexp: 1.in current buffer 2.in a file 3.in a directory (input 1~3): ") (cond ((string= type "1") (replall-regexp-in-curr-buffer)) ((string= type "2") (call-interactively #'replall-regexp-in-file)) ((string= type "3") (call-interactively #'replall-regexp-in-directory)) (t (message "please input 1~3!"))))
发布于 2020-06-16