【问题标题】:Insert Decimal After Character Match in Text File在文本文件中字符匹配后插入小数
【发布时间】:2017-07-13 12:36:19
【问题描述】:

我有一个包含一些数据值的 CSV 文件。当字符串有 3 个值时,我需要在第二个字符后插入小数点,当字符串有 4 个值时,我需要在第三个字符后插入一个小数点。

CSV 文件:

956,938,987,964,1004,934,1018,912

尝试的代码:

sed -e "s/\([0-9]\{2\}\)/\1./g"

当前结果:

95.6,93.8,98.7,96.4,10.04.,93.4,10.18.,91.2

预期结果:

95.6,93.8,98.7,96.4,100.4,93.4,101.8,91.2

我当前的代码(使用 sed)似乎适用于 3 值字符串,但在检测到 4 值字符串时失败。

【问题讨论】:

    标签: regex csv unix awk sed


    【解决方案1】:

    您可以将 2 个或更多数字捕获到 1 个组中,然后将一个尾随数字捕获到另一个组中:

    s='956,938,987,964,1004,934,1018,912'
    echo $s | sed 's/\([0-9]\{2,\}\)\([0-9]\)/\1.\2/g'
    

    查看online demo,输出:95.6,93.8,98.7,96.4,100.4,93.4,101.8,91.2

    详情

    • \([0-9]\{2,\}\) - 第 1 组:两位或更多 (\{2,\}) 位 ([0-9])
    • \([0-9]\) - 第 2 组:一位数。

    【讨论】:

      【解决方案2】:

      在 awk 中:

      $ awk '{gsub(/.(,|$)/,".&")}1' file
      95.6,93.8,98.7,96.4,100.4,93.4,101.8,91.2
      

      以防万一有空格或其他东西,您可以:

      $ awk '{gsub(/[0-9] *(,|$)/,".&")}1' file
      

      【讨论】:

        【解决方案3】:

        简单的替换怎么样

        \B([0-9])\b
        

        .\1
        

        喜欢

        sed 's/\B\([0-9]\)\b/.\1/g'
        

        解释:

        \B          如果匹配的位置是一个单词/数字序列(不是单词边界),则匹配 ([0-9]) 匹配捕获一个数字
        \b          如果匹配的位置在单词/数字边界

        中,则匹配

        通过您的示例,我收集到您只是希望所有数字都带有一位小数。这个正则表达式的作用是匹配并捕获多位数字中的最后一位数字。用 . 前面的自身替换它可以得到所需的输出。

        Online demohere at regex101 以获得更直观的说明。

        编辑

        如果 Wiktor 的担忧是一个问题,请将其更改为

        \B([0-9])([0-9])\b
        

        替换为

        \1.\2
        

        喜欢

        sed 's/\B\([0-9]\)\([0-9]\)\b/\1.\2/g'
        

        Here at regex101.

        【讨论】:

        • (\d)\b 也会在1 的情况下添加.。它将输出 .1 并且 OP 只需要添加 . 以防数字有 3+ 位(至少我这样理解)。 \B(\d)\b 将在 24 之间添加一个 . 24 (2.4) - 再次,不确定这是 OP 所期望的。
        • @WiktorStribiżew 是的。固定:)
        • 不确定,我更新了评论。此外,$1 没有在sed 中使用。符号是\1
        • 对于 sed/awk/grep/etc 的问题,请避免使用在线正则表达式网站...使用的正则表达式风格有很多不同。例如:\d 不适用于 sed , 需要使用[0-9] 代替...还有\b\B 特定于GNU sed,不适用于其他实现
        • @Sundeep 作为一个Windows老兄,我知道的并不多。更改为至少与 sed 兼容(因为在问题中用作示例)。经过测试和工作:)
        【解决方案4】:

        看起来您只是将所有数字除以 10,因此您可以使用这种非正则表达式方法:

        awk 'BEGIN{FS=OFS=","} {for (i=1; i<=NF; i++) $i/=10} 1' file
        
        95.6,93.8,98.7,96.4,100.4,93.4,101.8,91.2
        

        【讨论】:

        • 想法很好,但我认为您需要以特定格式打印...例如:echo '3453535235' | awk 'BEGIN{FS=OFS=","} {for (i=1; i&lt;=NF; i++) $i/=10} 1'3.45354e+08
        • 另外,echo 1000 | awk ... 输出 100。根据 OP 的需求,这可能是件好事。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-22
        • 2019-08-24
        • 1970-01-01
        • 2011-02-09
        • 1970-01-01
        • 2016-09-04
        • 2015-04-05
        相关资源
        最近更新 更多