【问题标题】:Split data separated by spaces用空格分隔数据
【发布时间】:2015-10-22 20:02:23
【问题描述】:

假设我有一个包含名称和寄存器的数据集

John Wayne 1234
Paul Newman 2345 Wrong register. The correct register is 2233
John Fitzgerald Kennedy 3456
Marilyn Monroe 1212

所有行都用空格分隔。我希望在 awk 中使用一个(或两个)正则表达式,它可以给我以下输出:

John Wayne
Paul Newman
John Fitzgerald Kennedy
Marilyn Monroe

1234
2233
3456
1212

我知道数据的格式非常非常糟糕,但有人知道如何帮助我吗?

【问题讨论】:

  • 您想要一个 awk 脚本来生成两个输出?或者可以接受有两个命令/脚本分别生成两个输出?
  • 可以有两个脚本。

标签: regex bash awk


【解决方案1】:

grep 可用于分别生成两个输出。看下面的测试:

$  cat f
John Wayne 1234
Paul Newman 2345 Wrong register. The correct register is 2233
John Fitzgerald Kennedy 3456
Marilyn Monroe 1212

输出一:

$  grep -o '^[^0-9]\+' f                                          
John Wayne 
Paul Newman 
John Fitzgerald Kennedy 
Marilyn Monroe

输出二:

$  grep -o '[0-9]\+$' f 
1234
2233
3456
1212

上面使用的正则表达式相对简单。使用相同的想法,如果您愿意,您也可以使用 sed 或 awk 应用正则表达式。

【讨论】:

  • 很好,但是第一个grep 命令在每个输出行上留下一个尾随空格。
【解决方案2】:

你可以使用sed:

sed 's/[[:blank:]]*[[:digit:]]\+.*$//' file
John Wayne
Paul Newman
John Fitzgerald Kennedy
Marilyn Monroe

sed 's/.*[[:blank:]]\([[:digit:]]\+\)$/\1/' file
1234
2233
3456
1212

【讨论】:

    【解决方案3】:

    聚会迟到了,但这可以让您同时完成两项工作:

    #!/usr/bin/awk -f
    
        {
            nums = nums "\n" $NF
            split($0, a, " [0-9]{4}")
            names = names a[1] "\n"
        }
    
    END {
            print names nums
        }
    

    首先,它获取该行的最后一个字段并将其添加到数字列表中。然后它在任何 4 位数字上拆分该行,并将拆分之前的部分添加到名称列表中。最后,它会打印名称列表和数字列表。

    输出:

    John Wayne
    Paul Newman
    John Fitzgerald Kennedy
    Marilyn Monroe
    
    1234
    2233
    3456
    1212
    

    如果担心多余的空格,请通过管道发送至cat -e,以明确可能出现空格的位置。

    【讨论】:

    • 做得很好,但您应该使用" [0-9]{4}"(注意前导空格)来消除名称后的尾随空格。此外,{ print names nums }(无逗号)将避免分隔线出现单个空格。也许您可以将 awk 命令重新格式化为多行以提高可读性,并提供示例输出。
    • 好建议。谢谢。
    • 感谢更新,++;请注意,类似 POSIX 的 shell(例如 bash)确实支持多行字符串文字,因此保留解决方案的 CLI 形式结合多行字符串提供两全其美:可读性,同时仍然能够将命令粘贴到终端以进行快速测试;有关示例,请参见 here
    【解决方案4】:

    这种情况相当简单,因为数字在最后一个分隔符之后,所以我们会将最后一列视为我们不知道它的内容,如下所示:

    awk '{print $NF}'
    

    对于其余部分,我们将简单地匹配所有字母,包括空格,直到我们找到一个非字母字符(例如数字),然后我们将所有其余部分替换为 null:

    sed 's/\([A-z ]*\) .*/\1/g'
    

    【讨论】:

    • 对一个聪明、实用的awk 解决方案表示敬意,但您的sed 命令会留下一个尾随空格;您可以在sed 脚本中附加第二个命令来补救:; s/ $//
    • 是的,很棒 (++) - 比我的建议更好。
    【解决方案5】:

    awk 允许您指定一个字符集作为字段分隔符。因此,如果你知道你的名字后面总是跟着数字,你可以使用:

    awk -F"[0-9]" '{print $1}' /tmp/x
    

    【讨论】:

    • 很好,但您只回答了一半问题(您只提取名称,而不是数字)。 -F"<space>[0-9]"<space> 我的意思是实际的空格字符。)将消除输出中的尾随空格。
    猜你喜欢
    • 2019-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    相关资源
    最近更新 更多