【问题标题】:Vim: Placing (,) in between CERTAIN high numbers IssueVim:在某些高数字之间放置(,)问题
【发布时间】:2017-11-06 18:20:48
【问题描述】:

源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 的山脉

【问题讨论】:

  • 19857694252432788 有何区别?
  • 一个数字可以 > 100 万吗?

标签: regex vim vi substitution


【解决方案1】:

你还没有告诉我们1985 和其他数字有什么区别,所以我假设你的“小”数字小于 2000。

你几乎明白了:

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

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

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

【讨论】:

  • 如果我没有高度低于 2000 的山脉,您的代码将是正确的。我的问题有点含糊,我会改写我的问题
【解决方案2】:

这一行将保持最后 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,我们可以找到其他解决方案。

更新

【讨论】:

  • 令人惊讶的是它给出了与我的代码相同的结果。你知道 vim 是否只能替换一些模式吗?我的问题其实无非就是替换3/4模式,听起来很简单。
  • @RobVanMeirvenne 添加了一个动画以显示它给出与您的代码相同的结果。你的输入是单行的,不是吗?
【解决方案3】:

我自己解决了这个问题,使用了 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

【讨论】:

    【解决方案4】:

    如果你想使用perl:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      • 2012-04-06
      • 1970-01-01
      • 2011-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多