【问题标题】:Awk splitting a line by spaces where there are spaces in each fieldawk 用空格分割一行,每个字段都有空格
【发布时间】:2015-07-18 18:04:11
【问题描述】:

我有一个像这样的 R 汇总表:

       employee     salary        startdate
 John Doe  :1   Min.   :21000   Min.   :2007-03-14
 Jolie Hope:1   1st Qu.:22200   1st Qu.:2007-09-18
 Peter Gynn:1   Median :23400   Median :2008-03-25
                Mean   :23733   Mean   :2008-10-02
                3rd Qu.:25100   3rd Qu.:2009-07-13
                Max.   :26800   Max.   :2010-11-01

我需要像这样生成一个输出 csv 文件:

employee,,salary,,startdate,,
John Doe,1,Min.,21000,Min.,2007-03-14
Jolie Hope,1,1st Qu.,22200,1st Qu.,2007-09-18
Peter Gynn,1,Median,23400,Median,2008-03-25
,,Mean,23733,Mean,2008-10-02
,,3rd Qu.,25100,3rd Qu.,2009-07-13
,,Max.,26800,Max.,2010-11-01

所以在 excel 中它看起来像这样:

但是用一个或多个空格分隔字段是不够的,

 awk -F "[ ]+" '{ print $3 }'

它适用于标题,但不适用于其余行:

salary
Doe
Hope:1
Gynn:1
:23733
Qu.:25100
:26800

这个问题可以使用 awk(也许还有 sed)解决吗?

【问题讨论】:

  • 使用 awk FIELDWIDTHS 而不是 FS 拆分?
  • 如果我只有一个文件可以工作,但它是否适用于多个输入文件,其中列数发生变化并且每列的字段类型可能不同?我唯一可以确定的是,如果您将输入文件视为具有三列,则每列中的字段都有一个“:”..
  • @SonicProtein 不,您甚至不确定这一点,因为您的示例中第一列的最后 3 行中的字段没有 :(它们只是空白)。您将不得不想出一些方法来描述工具如何识别字段的位置。如果字段不是固定宽度并且前导字段可能为空,那么工具如何判断第 3 行的 Mean :23733 是第一个字段还是第 2 个但第一个字段为空?
  • 使用 ("\t") 字符从R 导出数据?然后使用awk -f"\t" -v OFS="\t" '{awk program}'。祝你好运。
  • @Ed Morton,是的,你是对的,我会尝试找到一种方法来从 R 创建更好的输出。

标签: bash awk sed


【解决方案1】:
sed '1 {
   s/^[[:space:]]*\([^[:space:]]\{1,\}\)[[:space:]]\{1,\}\([^[:space:]]\{1,\}\)[[:space:]]\{1,\}[[:space:]]\{1,\}\([^[:space:]]\{1,\}\)/\1,,\2,,\3,/
   b
   }

s/[[:space:]]\{1,\}:/:/g

/^[[:space:]]*\([^:]\{1,\}\):\([^[:space:]]*\)[[:space:]]*\([^:]\{1,\}\):\([^[:space:]]*\)[[:space:]]*\([^:]\{1,\}\):\(.[^[:space:]]*\)/ {
   s//\1,\2,\3,\4,\5,\6/
   b
   }
/^[[:space:]]*\([^:]\{1,\}\):\([^[:space:]]*\)[[:space:]]*\([^:]\{1,\}\):\([^[:space:]]*\)/ {
   s//,,\1,\2,\3,\4/
   b
   }
' YourFile

sed 一个,只是为了好玩,如果你需要在这个 ArachnoRegEx 中稍微适应一下
在这种情况下,awk 更有趣,主要是为了以后添加的任何适应,但如果您只能访问 sed ...

【讨论】:

    【解决方案2】:

    这将 GNU awk 用于 FIELDWIDTHS 等,并依赖于标题后的第一行输入,始终填充所有字段。它包含只是 :s 的位置作为输出字段,如果您确实想使用此解决方案,我希望您能弄清楚如何跳过这些位置:

    $ cat tst.awk
    BEGIN { OFS="," }
    NR==1 {
        for (i=1;i<=NF;i++) {
            printf "%s%s", $i, (i<NF?OFS OFS OFS:ORS)
        }
        next
    }
    NR==2 {
        tail = $0
        while ( match(tail,/([^:]+):(\S+(\s+|$))/,a) ) {
            FIELDWIDTHS = FIELDWIDTHS length(a[1]) " 1 " length(a[2]) " "
            tail = substr(tail,RSTART+RLENGTH)
        }
        $0 = $0
    }
    {
        for (i=1;i<=NF;i++) {
            gsub(/^\s+|\s+$/,"",$i)
        }
        print
    }
    
    $ awk -f tst.awk file
    employee,,,salary,,,startdate
    John Doe,:,1,Min.,:,21000,Min.,:,2007-03-14
    Jolie Hope,:,1,1st Qu.,:,22200,1st Qu.,:,2007-09-18
    Peter Gynn,:,1,Median,:,23400,Median,:,2008-03-25
    ,,,Mean,:,23733,Mean,:,2008-10-02
    ,,,3rd Qu.,:,25100,3rd Qu.,:,2009-07-13
    ,,,Max.,:,26800,Max.,:,2010-11-01
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-16
      • 1970-01-01
      • 1970-01-01
      • 2012-04-22
      • 2012-09-22
      • 2016-03-29
      • 2012-02-26
      • 1970-01-01
      相关资源
      最近更新 更多