如何用Vim命令提取括号内数字并清理第六字段无关内容?
需求说明
需将每行前5个分号分隔的字段完整保留,把第6字段替换为该字段内所有括号中的数字的拼接结果,同时忽略人名里的数字(比如50 Cent中的50)。
原始文本示例
Stroszek;12/01/1977;5.74;Drama,Comedy;7.142;Bruno S.(2),Eva Mattes(1),50 Cent(2),Wilhelm von Homburg(2),Burkhard Driest(2),Clayton Szalpinski(0),Ely Rodriguez(0),Alfred Edel(0),Scott McKain(0),Pitt Bedewitz(0),Ralph Wade(0),Michael Gahr(2),Vaclav Vojta(0),Yüksel Topcugürler(0) Patients;01/03/2017;5.889;Drama,Comedy;25.000;Pablo Pauly(2),Soufiane Guerrab(2),Moussa Mansaly(2),Nailia Harzoune(1),Franck Falise(0),Yannick Renier(2),Alban Ivanov(2),Jason Divengele(0),Côme Levin(2),Dominique Blanc(1),Anne Benoît(1),Rabah Nait Oufella(2) Carnage;16/09/2011;9.4;Drama,Comedy;45.454;Kate Winslet(1),Jodie Foster(1),Christoph Waltz(2),John C. Reilly(2),Elvis Polanski(0),Eliot Berger(0),Julie Adams(1),Joseph Rezwin(2),Tanya Lopert(1),Nathan Rippy(2),Lexie Kendrick(1)
目标格式示例
Stroszek;12/01/1977;5.74;Drama,Comedy;7.142;21222000000200 Patients;01/03/2017;5.889;Drama,Comedy;25.000;222102202112 Carnage;16/09/2011;9.4;Drama,Comedy;45.454;11220012121
正确Vim命令解决方案
:%s/\v(([^;]+;){5}).*/\=submatch(1) . substitute(submatch(0), '[^()]*\((\d)\)[^;]*', '\1', 'g')
命令拆解说明
%s/:对所有行执行全局替换操作- 匹配规则
\v(([^;]+;){5}).*:\v:开启Vim的"非常魔法模式",简化正则表达式的符号写法(([^;]+;){5}):精准捕获每行前5个分号分隔的字段(包含每个字段末尾的分号),作为第一个子匹配结果.*:匹配第6字段及之后的所有内容
- 替换规则
\=submatch(1) . substitute(submatch(0), '[^()]*\((\d)\)[^;]*', '\1', 'g'):\=:启用Vim表达式作为替换内容(而非固定字符串)submatch(1):直接保留前5个字段的原始内容.:Vim中的字符串连接符号substitute(...):专门处理第6字段的内容,提取并拼接括号内的数字:submatch(0):当前行的完整文本内容'[^()]*\((\d)\)[^;]*':匹配"任意非括号字符+括号包裹的单个数字+到分号前的任意字符"的结构,仅捕获括号内的数字'\1':将匹配到的结构替换为捕获到的数字'g':全局替换,提取所有符合条件的数字并自动拼接
可选分步实现方式
如果觉得单条命令过于复杂,可分两步执行:
- 提取第6字段内所有括号数字并拼接,替换原第6字段:
:%s/\v(([^;]+;){5})(.*)/\1\=substitute(submatch(3), '[^()]*\((\d)\)[^,]*', '\1', 'g')
- 清理可能残留的多余逗号(实际第一步已处理,可作为兜底验证):
:%s/\v(([^;]+;){5}),*/\1/
内容的提问来源于stack exchange,提问作者Ewoud Noe
相关产品推荐
相关产品推荐

