【问题标题】:Fill empty columns in text file with 0用 0 填充文本文件中的空列
【发布时间】:2013-04-13 22:38:12
【问题描述】:

我有一个数据集,我从 Google 电子表格剪切并粘贴到我的文本编辑器 (Sublime Text 2) 中,该数据集与我的处理需求不完全匹配。

在它来自电子表格的形式中,数据以一行字符串开始,每列一个字符串,然后是多行数据;在数据行中,每一列的值要么为1,要么为空白。我不知道数据来自电子表格时是否是制表符分隔的,但是在将其粘贴到文本文件中之后却不是。如果一行中的最后一个1不在最后一列,则该行将用空格填充,直到但不包括最后一列。

我尝试使用awk 做一些事情,但我不知道如何解决空格既是分隔符又是列值的事实。接下来,我用sed 尝试了一些命令,包括用零替换重复的空格,并用管道连接到另一个sed,用1 0 替换10,但后来我有时会插入额外的零,我不知道在哪里在发生的相应行中。

这是一些示例数据(实际文件中有 13 列)。我已将$ 添加为该行最后一个字符之后的字符,因此您可以看到这些行被填充了多远。

"1" "2" "3" "4"                           "1" "2" "3" "4"
  1 1 $                                   0 1 1 0
1     1 $                                 1 0 0 1
  1   $                                   0 1 0 0
1 1   1 $                                 1 1 0 1

我想得到类似右边的东西(然后我不关心行结束的地方),所以我可以用awk 处理它。

顺便说一下,我已经看到了this question,这并没有解决我的问题,因为那里的解决方案基于文件是制表符分隔的事实,在全部在“空”单元格中。重申一下,我的文件是用空格分隔的,空单元格中有空格。

【问题讨论】:

    标签: awk text-files post-processing


    【解决方案1】:

    试图解释为什么一个问题很难,这有助于你有机会解决它。正因为想到这里的解释,我也想出了一个解决办法=)

    该解决方案适用于sed,基本上分三个步骤:

    1. 用 0 替换所有空的 first 列:

      cat datafile.txt | sed 's/^ /0 /g'
      
    2. 用 0 替换所有空的 last 列:

      cat datafile.txt | sed 's/^ /0 /g' | sed 's/  $/  0/g'
      

      在这里,我不得不对正则表达式中的空格数量进行一些试验,以将所有新零对齐。

    3. 用 0 替换所有空的 inner 列:

      cat datafile.txt | sed 's/^ /0 /g' | sed 's/  $/  0/g' | sed 's/  / 0/g'
      

      在这里,我还尝试将 0 放在替换正则表达式中的第一个或最后一个以使其正确。

    当然,完成此操作后,我通过在末尾标记> datafile-clean.txt 将输出重定向到文件。

    可能有一种更优雅的方法可以做到这一点,所以如果你有,请发布它,即使我个人不再需要该解决方案。

    更新: 如 cmets 所示,这个解决方案可以改进很多。我将在此处保留原始解决方案,因为我认为它的作用和顺序更清楚,但可能应该改用它。

    首先,我们不需要那么多管道;相反,我们在sed 上使用-e 标志:

    sed -e 's/^  /0 /' -e 's/  $/ 0/' -e 's/  / 0/g' datafile.txt
    

    这可以按原样工作,因为带有列标题的第一行没有任何双空格。如果是这样,则可以使用tail -n +2 datafile 读取文件,然后通过管道传输到上述sed 命令。

    【讨论】:

    • 请不要使用cat file|sed ...!你只是白白浪费资源。请改用sed ...<file!或者更方便的sed ... file 表格。据我所知,sed 可以处理多个规则定义。所以只使用一个sed
    • 对于像/^...//...$/ 这样的模式真的需要g 吗?它们只能匹配一次。
    • 不幸的是,没有与/ $/ 模式匹配的大小写。最后一个字符总是一个空格。
    • @TrueY:实际上,在行结束之前存在多个空格的情况 - 不幸的是,由于示例行选择不当,这在我提供的数据中没有显示。我已经更新以反映这一点。
    • 目前还不清楚每行添加了多少尾随空格。在第二个输入行中只有一个尾随空格,但必须添加一个零。但在第 3 行还有一个尾随空格,如果以一个结尾。所以我的解决方案不计算尾随空格的数量。
    【解决方案2】:

    我的第一次尝试并不成功。所以我的 2nd 3rd 第四次尝试根据修改后的输入自动确定列数:

    awk 'NR==1{for(;N<NF;++N)sp=" 0"sp}NR>1{$0=" "$0;sub(" +$","");gsub("  "," 0");$0=substr($0sp,2,2*N-1)}1'<<EOT
    "1" "2" "3" "4"
      1 1 
    1     1 
      1   
    1 1   1 
    EOT
    

    第一个空格是偶数,中间是奇数,所以我在开头添加了一个空格,以便在两种情况下使用相同的 gsub。目前尚不清楚存在多少尾随空格,因此脚本只是将它们切碎。它包含0 的字段次数。 Substr 从 2 开始剪掉添加的前导空格,持续到(number of fields)*2-1 个字符剪掉尾部空格。

    输出:

    "1" "2" "3" "4"
    0 1 1 0
    1 0 0 1
    0 1 0 0
    1 1 0 1
    

    【讨论】:

    • 这是一个很好的解决方案,但我更喜欢一个独立于字段数量的解决方案,这样我可以将它重用于具有相同问题的其他数据文件。如果需要,添加一个变量(例如-v N=7)是可以的,但如果脚本本身是“NF-agnostic”,那就更好了......
    • @Thomas Lycken:好的,代码已修改。项目的数量可以从第一行确定。
    【解决方案3】:
    sed 's/ /0/g;s/10/1 /g;s/00/0 /g;s/$/0 /' datafile.txt | cut -c 1-7
    

    【讨论】:

      猜你喜欢
      • 2017-11-23
      • 2023-03-20
      • 2013-11-01
      • 1970-01-01
      • 2016-06-26
      • 1970-01-01
      • 2011-07-07
      • 2020-07-30
      • 2020-06-23
      相关资源
      最近更新 更多