如何使用 AWK 使用字符长度分隔列

问题描述 投票:0回答:4

我有一个数据,它没有根据正确的字段分隔符(这是 awk 擅长的)进行格式化。但是,我知道的是,数据是固定宽度的。

 NODE     S1           S2           S3           SINT         SEQV    
   1  0.14919     -0.58396E-001-0.71230      0.86149      0.77873     
   2  0.56037E-001 0.23261E-002-0.37154      0.42757      0.40341     
   3  0.52036E-001 0.19762E-001-0.27222      0.32426      0.30939     
   4  0.59765E-001 0.22059E-001-0.24529      0.30505      0.28806     
   5  0.70704E-001-0.51976E-002-0.13862      0.20932      0.18354     
   6  0.11906      0.44607E-001-0.17493      0.29399      0.26474     
   7  0.25540      0.95993E-002-0.43110      0.68650      0.60246     
   8  0.52246E-001-0.47008E-001-0.35167      0.40391      0.36456     
   9  0.32215E-001-0.62291E-001-0.28800      0.32021      0.28497     
  10  0.28072E-001-0.68269E-001-0.28304      0.31111      0.27586     
  11  0.25990E-001-0.78663E-001-0.28626      0.31225      0.27527     
  12  0.26657E-001-0.79217E-001-0.29507      0.32173      0.28400     

预期的输出是这样的(其他列中的数字可以具有类似于 S2 中数据其他部分的格式):

  NODE       S1           S2           S3           SINT         SEQV    
   1    0.14919       -0.58396E-001  -0.71230      0.86149      0.77873     
   2    0.56037E-001   0.23261E-002  -0.37154      0.42757      0.40341     
   3    0.52036E-001   0.19762E-001  -0.27222      0.32426      0.30939     
   4    0.59765E-001   0.22059E-001  -0.24529      0.30505      0.28806     
   5    0.70704E-001  -0.51976E-002  -0.13862      0.20932      0.18354     
   6    0.11906        0.44607E-001  -0.17493      0.29399      0.26474     
   7    0.25540        0.95993E-002  -0.43110      0.68650      0.60246     
   8    0.52246E-001  -0.47008E-001  -0.35167      0.40391      0.36456     
   9    0.32215E-001  -0.62291E-001  -0.28800      0.32021      0.28497     
  10    0.28072E-001  -0.68269E-001  -0.28304      0.31111      0.27586     
  11    0.25990E-001  -0.78663E-001  -0.28626      0.31225      0.27527     
  12    0.26657E-001  -0.79217E-001  -0.29507      0.32173      0.28400     

主要问题是,有时列之间用空格分隔,有时没有空格(“-”号占据空格),即没有正确的字段分隔符。我发现了一个类似的问题here,但该数据在字段分隔符方面是一致的。根据我的想法,可能有两种方法

  1. 使用字符长度。例如,从第二行开始,每行字符不是 74 就是 75。
  2. 使用字段宽度:不知道AWK是否可以。

我是 AWK 新手,我知道使用其他一些工具可能会很容易,但我想知道是否可以使用 awk 分离/提取这些列。我在 MacOS 的终端中使用 awk。

bash awk
4个回答
4
投票

您可以通过在 FIELDWIDTHS 块中指定

BEGIN
在 awk
中分割固定宽度文件中的字段:

$ cat test
NODE     S1           S2           S3           SINT         SEQV
   1  0.14919     -0.58396E-001-0.71230      0.86149      0.77873
   2  0.56037E-001 0.23261E-002-0.37154      0.42757      0.40341
   3  0.52036E-001 0.19762E-001-0.27222      0.32426      0.30939
   4  0.59765E-001 0.22059E-001-0.24529      0.30505      0.28806
   5  0.70704E-001-0.51976E-002-0.13862      0.20932      0.18354
   6  0.11906      0.44607E-001-0.17493      0.29399      0.26474
   7  0.25540      0.95993E-002-0.43110      0.68650      0.60246
   8  0.52246E-001-0.47008E-001-0.35167      0.40391      0.36456
   9  0.32215E-001-0.62291E-001-0.28800      0.32021      0.28497
  10  0.28072E-001-0.68269E-001-0.28304      0.31111      0.27586
  11  0.25990E-001-0.78663E-001-0.28626      0.31225      0.27527
  12  0.26657E-001-0.79217E-001-0.29507      0.32173      0.28400

$ awk 'BEGIN{ FIELDWIDTHS= "5 13 13 13 13"; OFS="|"}{$1=$1}1' test
NODE |    S1       |    S2       |    S3       |    SINT
   1 | 0.14919     |-0.58396E-001|-0.71230     | 0.86149
   2 | 0.56037E-001| 0.23261E-002|-0.37154     | 0.42757
   3 | 0.52036E-001| 0.19762E-001|-0.27222     | 0.32426
   4 | 0.59765E-001| 0.22059E-001|-0.24529     | 0.30505
   5 | 0.70704E-001|-0.51976E-002|-0.13862     | 0.20932
   6 | 0.11906     | 0.44607E-001|-0.17493     | 0.29399
   7 | 0.25540     | 0.95993E-002|-0.43110     | 0.68650
   8 | 0.52246E-001|-0.47008E-001|-0.35167     | 0.40391
   9 | 0.32215E-001|-0.62291E-001|-0.28800     | 0.32021
  10 | 0.28072E-001|-0.68269E-001|-0.28304     | 0.31111
  11 | 0.25990E-001|-0.78663E-001|-0.28626     | 0.31225
  12 | 0.26657E-001|-0.79217E-001|-0.29507     | 0.32173

$ awk 'BEGIN{ FIELDWIDTHS= "5 13 13 13 13"; OFS="\t"}{$1=$1}1' test
NODE        S1              S2              S3              SINT
   1     0.14919        -0.58396E-001   -0.71230         0.86149
   2     0.56037E-001    0.23261E-002   -0.37154         0.42757
   3     0.52036E-001    0.19762E-001   -0.27222         0.32426
   4     0.59765E-001    0.22059E-001   -0.24529         0.30505
   5     0.70704E-001   -0.51976E-002   -0.13862         0.20932
   6     0.11906         0.44607E-001   -0.17493         0.29399
   7     0.25540         0.95993E-002   -0.43110         0.68650
   8     0.52246E-001   -0.47008E-001   -0.35167         0.40391
   9     0.32215E-001   -0.62291E-001   -0.28800         0.32021
  10     0.28072E-001   -0.68269E-001   -0.28304         0.31111
  11     0.25990E-001   -0.78663E-001   -0.28626         0.31225
  12     0.26657E-001   -0.79217E-001   -0.29507         0.32173

可能需要对这里构成实际字段的内容进行一些调整,但这就是要点。


2
投票

您还可以使用正则表达式解析您的数字格式并在每个数字之前插入空格:

awk 'NR==1 { print; next } { print gensub(/(-?[0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)?)/," \\1", "g") }' FILE

输出:

NODE     S1           S2           S3           SINT         SEQV    
    1   0.14919      -0.58396E-001 -0.71230       0.86149       0.77873     
    2   0.56037E-001  0.23261E-002 -0.37154       0.42757       0.40341     
    3   0.52036E-001  0.19762E-001 -0.27222       0.32426       0.30939     
    4   0.59765E-001  0.22059E-001 -0.24529       0.30505       0.28806     
    5   0.70704E-001 -0.51976E-002 -0.13862       0.20932       0.18354     
    6   0.11906       0.44607E-001 -0.17493       0.29399       0.26474     
    7   0.25540       0.95993E-002 -0.43110       0.68650       0.60246     
    8   0.52246E-001 -0.47008E-001 -0.35167       0.40391       0.36456     
    9   0.32215E-001 -0.62291E-001 -0.28800       0.32021       0.28497     
   10   0.28072E-001 -0.68269E-001 -0.28304       0.31111       0.27586     
   11   0.25990E-001 -0.78663E-001 -0.28626       0.31225       0.27527     
   12   0.26657E-001 -0.79217E-001 -0.29507       0.32173       0.28400  

使用此方法,您不必知道字段数量和字段宽度,因此它可以更稳健地应对数据格式更改。


0
投票

虽然 JNevillAndriy Makukha 的答案本身就很好,但我想专门使用 NAWK(MacOS 默认 AWK)来解决问题。我发现“FIELDWIDTHS”是 gawk 独有的功能Grymoiremachelp

问题是使用

FS=""

它将把每个字符视为一个字段。由于字段宽度相等,因此当知道每列中的字符数时,可以提取每列。例如,如果我想提取第一、第二、第三和最后一列,我可以使用以下代码(如果源数据命名为:test_input.txt):

awk 'BEGIN{FS=""}{print $1$2$3$4"\t"$5$6$7$8$9$10$11$12$13$14$15$16$17$18"\t"$19$20$21$22$23$24$25$26$27$28$29$30$31"\t"$59$60$61$62$63$64$65$66$67$68$69$70}' test_input.txt

输出:

NODE         S1             S2             SEQV    
   1      0.14919       -0.58396E-001   0.77873     
   2      0.56037E-001   0.23261E-002   0.40341     
   3      0.52036E-001   0.19762E-001   0.30939     
   4      0.59765E-001   0.22059E-001   0.28806     
   5      0.70704E-001  -0.51976E-002   0.18354     
   6      0.11906        0.44607E-001   0.26474     
   7      0.25540        0.95993E-002   0.60246     
   8      0.52246E-001  -0.47008E-001   0.36456     
   9      0.32215E-001  -0.62291E-001   0.28497     
  10      0.28072E-001  -0.68269E-001   0.27586     
  11      0.25990E-001  -0.78663E-001   0.27527     
  12      0.26657E-001  -0.79217E-001   0.28400

这是一个简单但有些不复杂的解决方案,但它目前对我来说适用于大数据。欢迎任何进一步的改进...


0
投票

使用任何 awk:

$ awk 'NR>1{$0=substr($0,1,18) OFS substr($0,19,13) OFS substr($0,32)} 1' file
 NODE     S1           S2           S3           SINT         SEQV
   1  0.14919      -0.58396E-001 -0.71230      0.86149      0.77873
   2  0.56037E-001  0.23261E-002 -0.37154      0.42757      0.40341
   3  0.52036E-001  0.19762E-001 -0.27222      0.32426      0.30939
   4  0.59765E-001  0.22059E-001 -0.24529      0.30505      0.28806
   5  0.70704E-001 -0.51976E-002 -0.13862      0.20932      0.18354
   6  0.11906       0.44607E-001 -0.17493      0.29399      0.26474
   7  0.25540       0.95993E-002 -0.43110      0.68650      0.60246
   8  0.52246E-001 -0.47008E-001 -0.35167      0.40391      0.36456
   9  0.32215E-001 -0.62291E-001 -0.28800      0.32021      0.28497
  10  0.28072E-001 -0.68269E-001 -0.28304      0.31111      0.27586
  11  0.25990E-001 -0.78663E-001 -0.28626      0.31225      0.27527
  12  0.26657E-001 -0.79217E-001 -0.29507      0.32173      0.28400
© www.soinside.com 2019 - 2024. All rights reserved.