我有一个数据,它没有根据正确的字段分隔符(这是 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,但该数据在字段分隔符方面是一致的。根据我的想法,可能有两种方法
我是 AWK 新手,我知道使用其他一些工具可能会很容易,但我想知道是否可以使用 awk 分离/提取这些列。我在 MacOS 的终端中使用 awk。
您可以通过在 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
可能需要对这里构成实际字段的内容进行一些调整,但这就是要点。
您还可以使用正则表达式解析您的数字格式并在每个数字之前插入空格:
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
使用此方法,您不必知道字段数量和字段宽度,因此它可以更稳健地应对数据格式更改。
虽然 JNevill 和 Andriy Makukha 的答案本身就很好,但我想专门使用 NAWK(MacOS 默认 AWK)来解决问题。我发现“FIELDWIDTHS”是 gawk 独有的功能Grymoire,machelp。
问题是使用
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
这是一个简单但有些不复杂的解决方案,但它目前对我来说适用于大数据。欢迎任何进一步的改进...
使用任何 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