【问题标题】:sed - Replace comma after first regex matchsed - 在第一次正则表达式匹配后替换逗号
【发布时间】:2019-10-06 16:19:13
【问题描述】:

我正在尝试对通用格式的行执行以下替换:

BBBBBBB.2018_08,XXXXXXXXXXXXX,01/01/2014,"109,07",DF,CCCCCCCCCCC, .......

如您所见,问题在于它是一个逗号分隔的文件,其中包含一个逗号小数的特定字段。我想用一个点来代替它。

我试过这个,以替换匹配后第一次出现的模式,但无济于事,有人可以帮助我吗?

sed -e '/,"/!b' -e "s/,/./"
sed -e '/"/!b' -e ':a' -e "s/,/\./"

提前致谢。 awk 或 perl 解决方案也会对我有所帮助。这是一个 awk 的努力:

gawk -F "," 'substr($10, 0, 3)==3 && length($10)==12 { gsub(/,/,".", $10); print}'

这产生了相同的文件不变。

【问题讨论】:

    标签: perl text awk sed replace


    【解决方案1】:

    CSV 文件应该在awk 中使用适当的FPAT 变量进行解析,该变量定义了构成此类文件中有效字段 的内容。一旦你这样做了,你就可以遍历字段来做你需要的替换

    gawk 'BEGIN { FPAT = "([^,]+)|(\"[^\"]+\")"; OFS="," } 
           { for(i=1; i<=NF;i++) if ($i ~ /[,]/) gsub(/[,]/,".",$i);}1' file
    

    请参阅 this answer of mine 以了解如何使用 FPAT 变量定义和解析 CSV 文件内容。另请参阅 Save modifications in place with awk 进行就地文件修改,例如 sed -i''

    【讨论】:

    • 你不需要if ($i ~ /[,]/) - 如果[,] 不匹配,gsub(/[,]/...) 就不会做任何事情。这也会删除空字段 - 您应该在 FPAT 设置中使用 *s 而不是 +s。
    【解决方案2】:

    以下sed 将转换带引号的数字字段中的所有小数分隔符:

     sed 's/"\([-+]\?[0-9]*\)[,]\?\([0-9]\+\([eE][-+]\?[0-9]+\)\?\)"/"\1.\2"/g'
    

    见:https://www.regular-expressions.info/floatingpoint.html

    【讨论】:

      【解决方案3】:

      这可能对你有用(GNU sed):

      sed -E ':a;s/^([^"]*("[^",]*"[^"]*)*"[^",]*),/\1./;ta' file
      

      此正则表达式匹配一对" 中的,,并将其替换为.。正则表达式锚定到行首,因此需要重复,直到没有更多匹配可以匹配,因此 :ata 命令会导致在任何替换成功时迭代替换。

      注意该解决方案期望所有双引号都匹配并且没有双引号被引用,即\" 不会出现在一行中。

      【讨论】:

        【解决方案4】:

        如果您的输入始终遵循仅包含 1 个逗号的引用字段的格式,那么您只需要:

        $ sed 's/\([^"]*"[^"]*\),/\1./' file
        BBBBBBB.2018_08,XXXXXXXXXXXXX,01/01/2014,"109.07",DF,CCCCCCCCCCC, .......
        

        如果比这更复杂,请参阅What's the most robust way to efficiently parse CSV using awk?

        【讨论】:

          【解决方案5】:

          假设你有这个: BBBBBBB.2018_08,XXXXXXXXXXXXX,01/01/2014,"109,07",DF,CCCCCCCCCCC

          试试这个: awk -F',' '{print $1,$2,$3,$4"."$5,$6,$7}' filename | awk '$1=$1' FS=" " OFS=","

          输出将是: BBBBBBB.2018_08,XXXXXXXXXXXXX,01/01/2014,"109.07",DF,CCCCCCCCCCC

          您只需要知道字段编号即可替换它们之间的字段分隔符。

          【讨论】:

          • 为什么不在第一个awk中定义OFS=","呢?使用您当前的解决方案,您将销毁所有可能位于字符串中的空格。
          • 我想让它保持干净和简单。另外,我假设除了字段分隔符之外没有空格。
          • 但是如果你直接定义OFS,你就去掉了一个命令:awk '{print $1,$2,$3,$4"."$5,$6,$7}' FS="," OFS="," file
          • 好吧,你也可以这样做!感谢您的意见。
          【解决方案6】:

          为了在 perl 中使用正则表达式,您必须使用 -r 激活扩展正则表达式。 所以如果你想替换所有数字并省略 " 符号,那么你可以使用这个:

          echo 'BBBBBBB.2018_08,XXXXXXXXXXXXX,01/01/2014,"109,07",DF,CCCCCCCCCCC, .......'|sed -r 's/\"([0-9]+)\,([0-9]+)\"/\1\.\2/g'
          

          如果您只想替换第一个匹配项,您可以使用它:

          echo 'BBBBBBB.2018_08,XXXXXXXXXXXXX,01/01/2014,"109,07",DF,CCCCCCCCCCC, .......'|sed -r 's/\"([0-9]+)\,([0-9]+)\"/\1\.\2/1'
          

          https://www.gnu.org/software/sed/manual/sed.txt

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-17
            • 2019-04-14
            • 2021-07-31
            • 2022-01-11
            • 1970-01-01
            • 2015-04-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多