【问题标题】:Sorting the lines in a CSV according to those containing numbers and those without根据包含数字和不包含数字的行对 CSV 中的行进行排序
【发布时间】:2012-02-17 13:25:28
【问题描述】:

我有一个 4 列的 CSV 文件。我想对这些行进行排序,以便将第三列中某处包含任何数字的行推到文档的末尾,将第三列中没有数字的行放在开头。如何以这种方式对文件进行排序?

更新:

为了澄清,我需要在第三列的字母中移动包含任何数字(即匹配[0-9])的行(该行的第三列可能包含其他符号)。空格并不重要。例如

dog, eats chicken, has 4 legs, does not like cats
cat, eats mice, has a tail, does not like water
mouse, eats bugs, has 4 legs, does not like cats
elephant, eats peanuts, has a trunk, does not like mice

将被排序到:

cat, eats mice, has a tail, does not like water
elephant, eats peanuts, has a trunk, does not like mice
dog, eats chicken, has 4 legs, does not like cats
mouse, eats bugs, has 4 legs, does not like cats

【问题讨论】:

    标签: bash shell sorting csv awk


    【解决方案1】:

    这将保持处理行的顺序以及不使用管道和外部命令。

    awk -F, '
    $3~/[0-9]+/{a[++i]=$0;x=i;next}1
    END{for(i=1;i<=x;i++) print a[i]}' file
    

    输入文件:

    [jaypal:~/Temp] cat file
    dog, eats chicken, has 4 legs, does not like cats
    cat, eats mice, has a tail, does not like water
    mouse, eats bugs, has 4 legs, does not like cats
    elephant, eats peanuts, has a trunk, does not like mice
    

    测试:

    [jaypal:~/Temp] awk -F, '
    $3~/[0-9]+/{a[++i]=$0;x=i;next}1
    END{for(i=1;i<=x;i++) print a[i]}' file
    cat, eats mice, has a tail, does not like water
    elephant, eats peanuts, has a trunk, does not like mice
    dog, eats chicken, has 4 legs, does not like cats
    mouse, eats bugs, has 4 legs, does not like cats
    

    【讨论】:

    • 我尝试使用awkmawk,但得到“第 1 行:END 或附近的语法错误”和“第 1 行:对数组 a 的非法引用”。
    • 这很奇怪……我尝试了awkgawk,它没有报告任何错误。您是否对脚本进行了任何更改?
    • 很抱歉,看起来 length(a) 引用导致您的 awk 版本出现问题。您能否尝试更新的解决方案。我进行了更改以删除该功能。
    【解决方案2】:

    这是 awk 中的一个简短的 1-liner,不需要调用其他实用程序,例如 sort

    awk -F',' '$3 ~ /[[:digit:]]/{a[$0];next}1; END{for(i in a)print i}' ./infile
    

    说明

    • 如果第三个字段包含数字,则将当前行作为键存储在数组“a”中并处理下一行
    • 如果所有行不符合上述规则,则按原样输出
    • 处理完所有行后,输出我们存储在数组“a”中的行

    输出

    $ awk -F',' '$3 ~ /[[:digit:]]/{a[$0];next}1; END{for(i in a)print i}' ./infile
    cat, eats mice, has a tail, does not like water
    elephant, eats peanuts, has a trunk, does not like mice
    mouse, eats bugs, has 4 legs, does not like cats
    dog, eats chicken, has 4 legs, does not like cats
    

    【讨论】:

    • 这段代码似乎只对第三行仅包含数字的行进行排序。我需要对至少包含一个数字的行进行排序,但它们可能在同一单元格中有其他字符。
    • 你试过运行它吗?它适用于您的新示例输入。正则表达式$3 ~ /[[:digit:]]/ 匹配任何包含至少一位数字的第三个字段,而不管它主要包含的其他内容。
    【解决方案3】:

    这样的事情应该可以工作:

    awk 'BEGIN {FS=","; OFS=","}; {print match($3,/[0-9]/), $0}' <file> | sort | cut -d, -f2-
    

    策略是

    • 使用awk在每行的开头插入找到数字的索引(如果没有找到数字,则为0)
    • 使用sort对所有行进行排序
    • 最后,使用cut 删除awk 前面的数字。

    【讨论】:

    • 我需要在第三列中搜索至少包含一个数字的单元格,而不仅仅是只包含数字的单元格。
    • @Village 我明白了,我已经修改了我的答案以考虑到这一点。
    【解决方案4】:

    这可能对你有用:

    sed 'h;s/,/\n/2;s/.*\n/0/;s/,.*//;s/[^0-9]//g;G;s/\n/\t/' file | 
    sort -k1,1n -k2 | 
    cut -f2
    

    解释:

    • 使用第 3 列中的数字生成数字键(如果没有,则将键设置为 0)
    • 按上述键排序,再按原文件排序
    • 去掉数字键

    【讨论】:

    • |放在行尾是什么意思?
    • @Village 这是管道命令。这是一个单行解决方案,我只是将其拆分以使其更易于阅读,
    猜你喜欢
    • 2016-03-17
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    • 2016-10-28
    • 2020-02-18
    • 2013-08-27
    相关资源
    最近更新 更多