Vim:放置(,)介于某些高数字问题之间

时间:2017-11-06 18:20:48

标签: regex vim vi substitution

source txt文件:

34|Gurla Mandhata|7694|25243|2788|Nalakankar Himalaya|30°26'19"N
81°17'48"E|Dhaulagiri|1985|6 (4)|China

命令输入:

:%s/\(\d\+\)\(\d\d\d\)/\1,\2/g

命令输出:

34|Gurla Mandhata|7,694|25,243|2,788|Nalakankar Himalaya|30°26'19"N
81°17'48"E|Dhaulagiri|1,985|6 (4)|China

期望的输出:

34|Gurla Mandhata|7,694|25,243|2,788|Nalakankar Himalaya|30°26'19"N
81°17'48"E|Dhaulagiri|1985|6 (4)|China

基本上 1985应该是1985而不是1,985。我尝试将\?设置为每次模式匹配时停止,然后°+,因此它必须检测到°以匹配模式,但没有成功。它只是替换°之前的所有内容,完全混乱。

我对正则表达式的了解与替补相结合很弱,而且我被困在这里。

编辑

前3个数字代表山脉的高度,3个数字需要用(,)改变,最后一个数字(1985)代表一年,不得改变。 数学解决方案不会成为漏洞,因为有高度低于1900的山脉

4 个答案:

答案 0 :(得分:0)

您没有告诉我们1985和其他数字之间有什么区别,所以我认为您的“小”数字小于2000。

你几乎得到了它:

:%s/(\d*[2-90])(\d\d\d)/\1,\2/g

或者,如果这不是你想要的,你可以使用c标志(:h s_flags):

:%s/\(\d\+\)\(\d\d\d\)/\1,\2/gc

答案 1 :(得分:0)

这一行将保留最后3列不变,只是替换它之前的内容:

%s/\v(.*)((\|[^|]*){3}$)/\=substitute(submatch(1),'\v(\d+)(\d{3})','\1,\2','g').submatch(2)/g

请注意,上述行会将1000000更改为1000,000而不是1,000,000。 Vim printf()不支持%'d,很可惜。如果你有数字> 1m,我们可以找到其他解决方案。

更新

enter image description here

答案 2 :(得分:0)

我自己解决了这个问题,使用了3个单独的命令;一个用于文件中的每个数字字符串:

%s/^\(\d*|[^|]*|\)\(\d\+\)\(\d\d\d\)|/\1\2,\3|/g :%s/^\(\d*|[^|]*|\d\+,*\d*|\)\(\d\+\)\(\d\d\d\)|/\1\2,\3|/g :%s/^\(\d*|[^|]*|\d\+,*\d*|\d\+,*\d*|\)\(\d\+\)\(\d\d\d\)|/\1\2,\3|/g

答案 3 :(得分:0)

如果您想使用perl

:%!perl -F'\|' -lane 'for(@F[2..4]) { s/(\d+)(\d{3})/\1,\2/;} print join "|", @F'