![删除仅包含数字的列](https://linux22.com/image/201179/%E5%88%A0%E9%99%A4%E4%BB%85%E5%8C%85%E5%90%AB%E6%95%B0%E5%AD%97%E7%9A%84%E5%88%97.png)
我有一个包含一些数据的表,我需要删除仅包含数字的列(Nr.,Cod,Tiraj):
Nr. Autor Titlu Cod Tiraj Tara
1 Gauss Carl Aritmetica 1 297485 11454 Germania
2 Gauss Carl Aritmatica 2 297484 10254 Germania
3 Gauss Carl Aritmetica 3 297455 45872 Germania
结果应该是这样的:
Autor Titlu Tara
Gauss Carl Aritmetica 1 Germania
Gauss Carl Aritmatica 2 Germania
Gauss Carl Aritmetica 3 Germania
列之间由TAB
我用这个创建了表:
.TS
tab(@);
c c c c c c .
Nr.@Autor@Titlu@Cod@Tiraj@Tara
1@Gauss Carl@Aritmetica 1@297485@11454@Germania
2@Gauss Carl@Aritmatica 2@297484@10254@Germania
3@Gauss Carl@Aritmetica 3@297455@45872@Germania
.TE
答案1
您想要从或多或少带有一些垃圾行并用作字段分隔符的CSV 数据集中删除NR.
,Cod
和列。Tiraj
@
sed -e 1,3d -e '$d' file |
csvcut -d @ -C 'Nr.,Cod,Tiraj' |
csvformat -D @
其输出将是
Autor@Titlu@Tara
Gauss Carl@Aritmetica 1@Germania
Gauss Carl@Aritmatica 2@Germania
Gauss Carl@Aritmetica 3@Germania
添加回sed
删除的内容并根据新的列数进行调整,然后将其写入新文件:
{
printf '%s\n' .TS 'tab(@);' 'l l l .'
sed -e 1,3d -e '$d' file |
csvcut -d @ -C 'Nr.,Cod,Tiraj' |
csvformat -D @
echo .TE
} >file.new
csvcut
和实用程序csvformat
是 csvkit 的一部分,csvkit 是一个用于处理 CSV 文件的工具包,可从https://csvkit.readthedocs.io/en/latest/
最终表格将使用 进行排版nroff -t file.new
。
您还可以通过运行初始管道的输出来获得表的变体column -s @ -t
:
$ sed -e 1,3d -e '$d' file | csvcut -d @ -C 'Nr.,Cod,Tiraj' | csvformat -D @ | column -s @ -t
Autor Titlu Tara
Gauss Carl Aritmetica 1 Germania
Gauss Carl Aritmatica 2 Germania
Gauss Carl Aritmetica 3 Germania
或者,您可以使用csvlook
:
$ sed -e 1,3d -e '$d' file | csvcut -d @ -C 'Nr.,Cod,Tiraj' | csvlook
| Autor | Titlu | Tara |
| ---------- | ------------ | -------- |
| Gauss Carl | Aritmetica 1 | Germania |
| Gauss Carl | Aritmatica 2 | Germania |
| Gauss Carl | Aritmetica 3 | Germania |
...取决于你是什么实际上想要作为输出。
答案2
尝试这个笨拙的概念证明。它基于列始终是数字或非数字的假设。
awk -F"\t" '
NR==1 {split($0, HDRSV) # save header fields for later use
next
}
NR==2 {for (i=1; i<=NF; i++) if ($i+0 != $i) PR[++IX] = i # check if column is non-numeric and
# save col nr for print
for (i=1; i<=IX; i++) printf "%s\t", HDRSV[PR[i]] # print header fields
printf ORS # and line terminator
}
{for (i=1; i<=IX; i++) printf "%s\t", $PR[i] # print each line´s fields
printf ORS # and line terminator
}
' file
Autor Titlu Tara
Gauss Carl Aritmetica1 Germania
Gauss Carl Aritmatica2 Germania
Gauss Carl Aritmetica3 Germania
答案3
使用乐(以前称为 Perl_6)
~$ cat authors.tr | raku -ne '.split( / [^ | \S] [\d+]+ %% "\@" /, :skip-empty).join("\@").put;' | raku -ne '++$ == 4 ?? .split("\@")[1,2,5].join("\@").put !! .put;' | nroff -t -Tascii
输入示例:
TS
tab(@);
c c c c c c .
Nr.@Autor@Titlu@Cod@Tiraj@Tara
1@Gauss Carl@Aritmetica 1@297485@11454@Germania
2@Gauss Carl@Aritmatica 2@297484@10254@Germania
3@Gauss Carl@Aritmetica 3@297455@45872@Germania
.TE
示例输出:
Autor Titlu Tara
Gauss Carl Aritmetica 1 Germania
Gauss Carl Aritmatica 2 Germania
Gauss Carl Aritmetica 3 Germania
作为一项挑战,我决定尝试编写一个 Raku 单行代码(好吧,两行代码:一行用于标题,一行用于数据列),以修改authors.tr
nroff/groff 源文件。一个棘手的方面是,很难确定整个字段是否仅由数字组成:内部(非最左/非最右)列肯定会被列分隔符包围,但终端(最左/最右)则不会。
我最终发现了这样一个事实:(至少对于给定的列)第一个正则表达式原子应该是[^ | \S]
.正则表达式的其余部分由 Raku 漂亮的“修改量词”处理%%
,它识别重复(按列)模式,例如[\d+]+ %% "\t"
,这意味着'一列或多列--\d+
由制表符分隔,允许尾随制表符'。上面的正则表达式删除所有以数字结尾的列,但前面包含空格的列除外(如列Aritmetica 1
)。
但实际上,这工作量太大了。更简单:
- 删除
.
line_#3 末尾的句点,并在 nroff/groff 列格式部分插入新的 line_#4,该部分指定N
数字列与A
字母列(非标题、数据), - 使用 Raku 解析标头(下面的示例使用
N A A N N A .
as new line_#4),并且 - 删除那些指定的列
N
。
~$ cat authors2.tr | raku -e 'my @a=lines; \
@a[2..3] = @a[2..3]>>.comb>>.[0,2,4...*]; \
@a[4..7].=map: *.split("\@", :skip-empty); \
my $n = @a[3].grep({!/ N /}, :k ).list; \
@a[2] = @a[2][ |$n.head(*-1)]; @a[3] = @a[3][ |$n]; \
@a[4..7].=map: *.[ |$n.head(*-1)].join("\@"); .put for @a;'
示例输出(有效 nroff/groff):
.TS
tab(@);
c c c
A A A .
Autor@Titlu@Tara
Gauss Carl@Aritmetica 1@Germania
Gauss Carl@Aritmatica 2@Germania
Gauss Carl@Aritmetica 3@Germania
.TE
示例输出(之后nroff -t -Tascii
):
Autor Titlu Tara
Gauss Carl Aritmetica 1 Germania
Gauss Carl Aritmatica 2 Germania
Gauss Carl Aritmetica 3 Germania
答案4
$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR==FNR {
if ( NR > 1 ) {
for ( i=1; i<=NF; i++ ) {
if ( $i != ($i+0) ) {
isGood[i]
}
}
}
next
}
{
out = sep = ""
for ( i=1; i<=NF; i++ ) {
if ( i in isGood ) {
out = out sep $i
sep = OFS
}
}
print out
}
$ awk -f tst.awk file file
Autor Titlu Tara
Gauss Carl Aritmetica 1 Germania
Gauss Carl Aritmatica 2 Germania
Gauss Carl Aritmetica 3 Germania