如何在Vi中批量删除PDB文件重复坐标原子行(无需手动确认)
在Vi/Vim或Emacs中批量去重PDB文件的重复坐标原子行
问题场景
我正在处理一个PDB文件,该文件包含大量原子及其坐标,示例行如下:
ATOM 1 ZN ZN2 Z 1 6.703 3.973 -2.488 1.00 0.00 ZINC ATOM 2 ZN ZN2 Z 1 -2.639 3.973 -2.488 1.00 0.00 ZINC文件中存在重复坐标的原子:三组坐标值重复出现,但每行的原子编号不同,导致整行不完全相同。希望保留每组重复坐标的一行,删除其余行,不关注顺序。目前采用手动搜索替换坐标为@@@再删除的方式:
:%s/6.703 3.973 -2.488/@@@/gc :g/@@@/d但文件过长,手动操作耗时易出错,求更简便的方法,优先Vi编辑器,Emacs也可。
Vi/Vim 解决方案
方法1:结合系统sort+uniq命令(快速高效)
利用外部命令按坐标排序后去重,适合大文件:
- 按坐标字段(第7-9列,空格分隔)排序:
:%!sort -k7,9 - 跳过前6个字段(原子编号等不重复内容),只比较后续内容去重,保留每组重复的第一行:
:%!uniq -f6
注:如果需要保留原始顺序,不推荐此方法;若对顺序无要求,这是最快的方式。
方法2:Vim内置脚本(保留原始顺序)
通过字典记录已出现的坐标,遍历文件删除重复行,不改变原有行的顺序:
在Vim命令行执行:
:let seen = {} :g/^ATOM/let coords = split(getline('.'))[6:8] | let key = join(coords, ' ') | if has_key(seen, key) | delete() | else | let seen[key] = 1 | endif
let seen = {}:创建空字典存储已出现的坐标:g/^ATOM/:对所有以ATOM开头的原子行执行后续逻辑split(getline('.'))[6:8]:拆分当前行为字段列表,提取第7-9个元素(坐标部分)- 若坐标已在字典中则删除当前行,否则将坐标存入字典标记为已出现
Emacs 解决方案
方法1:调用外部sort+uniq命令
- 选中整个文件(
C-x h) - 执行
M-x shell-command-on-region - 输入命令
sort -k7,9 | uniq -f6,回车后确认替换原内容即可
方法2:Elisp脚本(保留原始顺序)
在Emacs中执行以下脚本(可通过M-x eval-expression逐行执行,或写入临时脚本):
(let ((seen (make-hash-table :test 'equal))) (goto-char (point-min)) (while (not (eobp)) (let* ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position))) (fields (split-string line)) (coords (subseq fields 6 9)) (key (string-join coords " "))) (if (gethash key seen) (kill-whole-line) (puthash key t seen))) (forward-line 1)))
- 创建哈希表
seen记录已出现的坐标 - 从文件开头遍历每一行,提取坐标字段作为键
- 若坐标已存在则删除当前行,否则将坐标存入哈希表
内容的提问来源于stack exchange,提问作者user19619903
相关产品推荐
相关产品推荐

