如何高效地给多行文本添加前后缀

序言

理论上,开发人员是不允许操作生产环境的,更别说是像商品、订单这样的重要业务数据。不过对小公司来说,后台系统往往不是很完善,总有一些需求让运营或客服部门的同事操作起来捉襟见肘,不得不寻求开发人员的帮助。

通常这些部门的同事会给过来一批需要处理的商品或订单的ID,我会将它们粘贴到一个脚本中,并将脚本放到生产环境的机器上运行,以实现他们的ad hoc需求。ID一般用Excel文件,或在线文档的方式提供过来,将它们粘贴到脚本的源码中之后,还要为它们添加必要的引号和逗号,以满足所用语言的语法要求。比如下图就是直接粘贴后,VSCode提示错误的样子

那么,怎样才能不失逼格地给这批ID加上前后的引号及行末的逗号呢?

八仙过海,各显神通

有很多方法可以完成这个任务,比如借助VSCodemulti-cursor功能,手动添加前后缀

当要添加光标的位置处于同一列时,更适合用VSCode的另一个功能在下面添加光标(快捷键是command+option+↓)来实现,免去了一遍遍点击鼠标的烦恼。multi-cursor所敲入的每个光标还可以在各自的行上沿同方向移动不同的距离,适合处理每行长度不一致的情况。

也可以用Vim中的列编辑模式,操作体验差不多,还可以比VSCode按更少的键——起码不需要一直压着option键。

Vim列模式的效果

但列编辑模式不方便在行末追加内容——必须先在第一行的末尾敲入一个空格,往右移动依次光标,然后才能继续用列编辑模式批量添加后缀。

Emacs也有类似列编辑模式的功能,它的string-insert-rectangle命令比Vim的更便于添加后缀。但它没有默认的快捷键,需要先按下M-x,再输入命令名并回车,略为繁琐(尽管命令名可以自动补全)。

Emacs的string-insert-rectangle的效果

除了各家编辑器内置的功能,命令行工具也适合完成这种处理,比如可以用sed

➜  /tmp cat b
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
5FEB1AE4-239A-4276-8E37-BE913CE6D117
➜  /tmp sed -e "s/^/'/" -i '' b
➜  /tmp sed -e "s/$/',/" -i '' b
➜  /tmp cat b
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',
'5FEB1AE4-239A-4276-8E37-BE913CE6D117',

有些从在线文档上复制下来的ID会有一行空行存在于两两之间,如果是在命令行的话,只需要先用grep筛选一遍即可,可组合性比编辑器更强。

美中不足的是,用sed处理后需要手动将文件b的内容粘贴到脚本中——如果是用Emacs的话,也可以用C-x i让编辑器在光标处直接插入该文件的内容。

如果可以寸步不离Emacs,通过简单的命令或快捷键来完成这个操作,岂不美哉?

自己动手,丰衣足食

用上自定义的Elisp函数后的效果如下

其实实现思路很简单:

  1. 首先用户会选中一片要添加前后缀的区域;
  2. 使用buffer-substring-no-properties函数复制这个region中的字符串,绑定为text
  3. read-from-minibuffer提示并读取用户输入待添加的前后缀字符串;
  4. split-stringtext切割为一行行的字符串,给每一行添加前后缀,再用mapconcat拼回一个字符串;
  5. delete-region删除被选中的内容,然后用insert插入新的字符串。

最终的Elisp函数的定义如下

(defun lt--insert-at-start-end ()
  "为TEXT中的每一行添加PREFIX前缀和SUFFIX后缀。"
  (interactive)
  (let* ((text (buffer-substring-no-properties (mark) (point)))
         (prefix (read-from-minibuffer "插入的前缀:"))
         (suffix (read-from-minibuffer "插入的后缀:"))
         (lines (split-string text))
         (decorated-lines
          (mapcar (lambda (line)
                    (concat prefix line suffix))
                  lines))
         (new-text (mapconcat 'identity decorated-lines "\n")))
    (delete-region (mark) (point))
    (insert new-text)))

欢迎读者朋友中的Emacs用户也来使用使用;-)

阅读原文

169 声望
3.7k 粉丝
0 条评论
推荐阅读
如何在CommonLisp中解析命令行参数
clingon 是一个 Common Lisp 的命令行选项的解析器,它可以轻松地解析具有复杂格式的命令行选项。例如,下面的代码可以打印给定次数的打招呼信息

用户bPGfS阅读 610

封面图
一个HTTP请求的曲折经历
作为程序员的我们每天都在和网络请求打交道,而前端程序员接触的最多的就是HTTP请求。平时工作中,处理网络请求之类的操作是最多的了。但是一个请求从客户端发出到被服务端处理、再回送响应,再被客户端接收这一...

nero24阅读 5.1k评论 1

Nginx 一网打尽:动静分离、压缩、缓存、黑白名单、跨域、高可用、性能优化...
早期的业务都是基于单体节点部署,由于前期访问流量不大,因此单体结构也可满足需求,但随着业务增长,流量也越来越大,那么最终单台服务器受到的访问压力也会逐步增高。时间一长,单台服务器性能无法跟上业务增...

民工哥23阅读 1.1k

封面图
Golang 中 []byte 与 string 转换
string 类型和 []byte 类型是我们编程时最常使用到的数据结构。本文将探讨两者之间的转换方式,通过分析它们之间的内在联系来拨开迷雾。

机器铃砍菜刀24阅读 58.5k评论 2

最好用的 python 库合集
🎈 分词 - jieba优秀的中文分词库,依靠中文词库,利用词库确定汉子之间关联的概率,形成分词结果 {代码...} 🎈 词云库 - wordcloud对数据中出现频率较高的 关键词 生成的一幅图像,予以视觉上的突出 {代码...} 🎈 ...

tiny极客11阅读 2.9k评论 2

封面图
计算机网络连环炮40问
本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~

程序员大彬14阅读 1.9k

万字详解,吃透 MongoDB!
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常...

JavaGuide8阅读 1.8k

封面图
169 声望
3.7k 粉丝
宣传栏