【问题标题】:How to remove multiple commas but keep one in between two values in a csv file?如何删除多个逗号,但在 csv 文件中的两个值之间保留一个?
【发布时间】:2016-12-26 16:22:02
【问题描述】:

我有一个包含数百万条记录的 csv 文件,如下所示

1,,,,,,,,,,a,,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,456,,,,,,,,,,,,,,,,,,,,,3455,,,,,,,,,,
1,,,,,,,,,,b,,,,,,,,,,,,,,,,5,,,,,,,,,,,,,,,467,,,,,,,,,,,,,,,,,,,,,3445,,,,,,,,,,
2,,,,,,,,,,c,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,567,,,,,,,,,,,,,,,,,,,,,4656,,,,,,,,,,

我必须删除两个值之间多余的逗号并只保留一个。示例输入的输出应如下所示

1,a,4,456,3455
1,b,5,467,3445
2,c,6,567,4656

我如何使用 shell 来实现这一点,因为它也会自动处理其他文件。 我需要将此数据加载到数据库中。我们可以用 R 来做吗?

【问题讨论】:

  • awk -F',*' 'BEGIN{OFS=","}; {print $1,$2,$3,$4,$5}' file
  • @Cyrus 不错!应该得到一个正确的答案。
  • @Jean-FrançoisFabre:这仅适用于已知列数。
  • @Cyrus:您可以对字段数进行循环。但是是的sed 永远:) 虽然我听说awk 快一点。
  • 非常感谢。我没有提到我有很多像上面这样的列。在那种情况下它也可以工作吗?

标签: r bash shell csv command-line


【解决方案1】:

sed方法:

sed -e "s/,\+/,/g" -e "s/,$//" input_file > output_file

将多个逗号转换为单个逗号,并删除最后一个逗号。

【讨论】:

    【解决方案2】:

    编辑以解决修改后的问题。

    R 解决方案。

    提供的原始解决方案只是处理文本。假设您的行在一个结构中,您可以使用以下方式处理多行:

    # Create Data
    Row1 = "1,,,,,,,a,,,,,,,,,,4,,,,,,,,,456,,,,,,,,,,,3455,,,,,,,"
    Row2 = "2,,,,,,,b,,,,,,,,,,5,,,,,,,,,567,,,,,,,,,,,4566,,,,,,,"
    Rows = c(Row1, Row2)
    
    CleanedRows = gsub(",+", ",", Rows)           # Compress multiple commas
    CleanedRows = sub(",\\s*$", "", CleanedRows)  # Remove final comma if any
    [1] "1,a,4,456,3455" "2,b,5,567,4566"
    

    但如果您尝试从 csv 读取此内容并压缩行,

    ## Create sample data
    Data =read.csv(text="1,,,,,,,a,,,,,,,,,,4,,,,,,,,,456,,,,,,,,,,,3455,,,,,,,
    2,,,,,,,b,,,,,,,,,,5,,,,,,,,,567,,,,,,,,,,,4566,,,,,,,",
    header=FALSE)
    

    你的代码可能会说 Data = read.csv("YourFile.csv", header=FALSE)

    Data = Data[which(!is.na(Data[1,]))]
    Data
      V1 V8 V18 V27  V38
    1  1  a   4 456 3455
    2  2  b   5 567 4566
    

    注意:这假设非空白字段在每一行中的相同位置。

    【讨论】:

    • 我们是否需要使用 R 逐行执行?
    • 使用readLines 和gsub 代码清除多余的逗号可能会更快/更简单,然后才将剩余的内容解析到数据框中。
    【解决方案3】:

    使用tr -s:

    echo 'a,,,,,,,,b,,,,,,,,,,c' | tr -s ','
    

    输出:

    a,b,c
    

    如果输入行有尾随逗号,tr -s ',' 会将这些尾随逗号压缩成一个逗号,但要去掉这个逗号,需要添加一点 sed 代码:tr -s ',' | sed 's/,$//'。


    速度。对包含 OP 示例中的第一行的 10,000,000 行测试文件进行重复测试。

    1. 3 秒。 tr -s ','(但留下逗号)
    2. 9 秒。 tr -s ',' | sed 's/,$//
    3. 30 秒。 sed -e "s/,\+/,/g" -e "s/,$//" (Jean-François Fabre's answer.)

    【讨论】:

    • echo 'a,,,,,,,,b,,,,,,,,,,c,' | tr -s ',' 最后留下一个逗号。
    • @Jean-FrançoisFabre,是的,它确实无法删除最后一个逗号。附加| sed 's/,$//'(如您自己的答案)将解决该问题...
    • tr 通常比其他人更好,因为它更简单。在这种情况下,无论如何你都必须运行sed。但现在你的答案至少是正确的。
    【解决方案4】:

    如果您的文件确实是 CSV 文件,它可能会以几种不同的方式引用逗号,这会使基于正则表达式的 CSV 解析变得不愉快。

    我通常使用并推荐csvkit,它有一套很好的用于 shell 的 CSV 解析实用程序。文档http://csvkit.readthedocs.io/en/latest/

    您的确切问题已在 csvkit 中通过这组命令得到解答。首先,csvstat 显示文件的样子:

    $ csvstat -H --max tmp.csv | grep -v None 1. column1: 2 11. column11: c 27. column27: 6 42. column42: 567 63. column63: 4656

    那么,既然您知道所有数据都在这些列中,您可以运行以下命令:

    $ csvcut -c 1,11,27,42,63 tmp.csv 1,a,4,456,3455 1,b,5,467,3445 2,c,6,567,4656

    得到你想要的答案。

    【讨论】:

    • 谢谢你 vielmetti
    【解决方案5】:

    我们可以用 R 来做吗?

    如果你的输入如图所示,即你想跳过所有行中的相同列,你可以分析第一行,然后在read.table中定义列类:

    text <- "1,,,,,,,,,,a,,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,456,,,,,,,,,,,,,,,,,,,,,3455,,,,,,,,,,
             1,,,,,,,,,,b,,,,,,,,,,,,,,,,5,,,,,,,,,,,,,,,467,,,,,,,,,,,,,,,,,,,,,3445,,,,,,,,,,
             2,,,,,,,,,,c,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,567,,,,,,,,,,,,,,,,,,,,,4656,,,,,,,,,,"
    
    tmp <- read.table(text = text, nrows = 1, sep = ",")
    colClasses <- sapply(tmp, class)
    colClasses[is.na(unlist(tmp))] <- "NULL" 
    

    这里我假设第一行中没有实际的 NA 值。如果可以,您需要稍微调整一下。

    read.table(text = text, sep = ",", colClasses = colClasses)
    #  V1 V11 V27 V42  V63
    #1  1   a   4 456 3455
    #2  1   b   5 467 3445
    #3  2   c   6 567 4656
    

    显然,您应该指定 file 而不是 text。

    此解决方案对于小到中等大小的数据相当有效。对于大数据,将第二个 read.table 替换为包 data.table 中的 fread(但无论跳过列问题如何都适用)。

    【讨论】:

      猜你喜欢
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多