我有一堆文本,看起来像这样:
K1 CM1 TN1 CT14 D01
K2 CM2 TN2 CT15 D02
K3 CM3 TN3 CT16 D03
K4 CM4 TN4 CT17 D04
K5 CM5 TN5 CT18 D05
K6 CM6 TN6 CT19 D06
K7 CM11 TN7 CT20 D07
K8 CM12 TN8 D08
TW10 CM15 TN9 D09
TW11 TN10 D11
TW12 TN11 D12
TW16 TN12 D6W
(列可以为空,并由一个制表符分隔,而不是空格 - cas)
我想使用 BBedit 中的 Run Unix 命令功能将此文本转换为以下内容:
'K1',
'K2',
'K3',
'K4',
'K5',
'K6',
'K7',
'K8',
'TW10',
'TW11',
'TW12',
'TW16',
'CM1',
'CM2',
'CM3',
'CM4',
'CM5',
'CM6',
'CM11',
'CM12',
'CM15',
'TN1',
'TN2',
'TN3',
'TN4',
'TN5',
'TN6',
'TN7',
'TN8',
'TN9',
'TN10',
'TN11',
'TN12',
'CT14',
'CT15',
'CT16',
'CT17',
'CT18',
'CT19',
'CT20',
'D01',
'D02',
'D03',
'D04',
'D05',
'D06',
'D07',
'D08',
'D09',
'D11',
'D12',
'D6W'
正如您所看到的,每个字符串都用单引号引起来,并与最终字符串分开,后跟一个逗号。
提前致谢。
答案1
假设输入包含具有制表符分隔字段的行,并且您首先需要每行从上到下的第一个字段,然后是第二个字段等,再加上引号和逗号,这里有一些廉价的解决方案。
丑陋的两行最多 9 列(使用 sed 进行格式化):
for i in 1 2 3 4 5 6 7 8 9; do cut -f$i file.txt; done |
grep -v '^$' | sed -e "s/^/'/" -e "s/\$/'/" -e '$!s/$/,/'
使用 AWK 手动转置(加上 sed 删除最后一个逗号):
awk -F'\t' 'NF > cols {cols=NF}
{for (i=1; i<=NF; i++) { a[i,NR]=$i }}
END { for (j=1;j<=cols;j++) for (i=1;i<=NR;i++)
if (a[j, i] != "") printf "\047%s\047,\n", a[j, i] }' file.txt |
sed -e '$s/,$//'
使用 GNU datamash(以及用于格式化的 sed):
datamash --no-strict transpose < file.txt | tr -s '\t' '\n' |
sed -e "s/^/'/" -e "s/\$/'/" -e '$!s/$/,/'
(在 Linux 上测试,前两个也适用于 macOS)
答案2
您可能想尝试使用 grep 和 sed 的方法:
for i in K TW CM TN CT D ;do grep -ow $i[0-9]*[A-Z]* <input_file;done
如果您想将每个项目放在单引号中并在每行末尾添加逗号,则将上面的内容通过管道传输到此命令:
sed "s/$/\'\,/" | sed "s/^/\'/"
答案3
我不确定这the Run Unix command feature in BBedit
意味着什么,但如果您只是寻找一个 Unix 命令来根据您显示的输入生成您显示的输出,那么 - 使用任何 awk 并假设您的字段由制表符分隔:
$ cat tst.awk
BEGIN { FS="\t" }
{
for ( i=1; i<=NF; i++ ) {
if ( $i != "" ) {
a[i,NR] = $i
max_j[i] = NR
}
}
max_i = (max_i > NF ? max_i : NF)
}
END {
for ( i=1; i<=max_i; i++ ) {
for ( j=1; j<=max_j[i]; j++ ) {
printf "%s\047%s\047", sep, a[i,j]
sep = ",\n"
}
}
print ""
}
$ awk -f tst.awk file
'K1',
'K2',
'K3',
'K4',
'K5',
'K6',
'K7',
'K8',
'TW10',
'TW11',
'TW12',
'TW16',
'CM1',
'CM2',
'CM3',
'CM4',
'CM5',
'CM6',
'CM11',
'CM12',
'CM15',
'TN1',
'TN2',
'TN3',
'TN4',
'TN5',
'TN6',
'TN7',
'TN8',
'TN9',
'TN10',
'TN11',
'TN12',
'CT14',
'CT15',
'CT16',
'CT17',
'CT18',
'CT19',
'CT20',
'D01',
'D02',
'D03',
'D04',
'D05',
'D06',
'D07',
'D08',
'D09',
'D11',
'D12',
'D6W'
答案4
使用perl:
$ perl -lne '
# split each input line on single tabs (not one-or-more
# whitespace chars) into temporary array @F.
@F = split /\t/;
# Construct an Array-of-Arrays (AoA) containing the data.
# This works with any number of columns, not limited to 5.
# Assumes each input line has the same number of fields,
# although some may be empty.
foreach my $i (keys @F) {
if (length($F[$i]) > 0) {
push @{$columns[$i]}, "\047" . $F[$i] ."\047" ;
};
};
END {
# flatten the AoA with map and print it
print join(",\n", map { @$_ } @columns);
}' input.txt
'K1',
'K2',
'K3',
'K4',
'K5',
'K6',
'K7',
'K8',
'TW10',
'TW11',
'TW12',
'TW16',
'CM1',
'CM2',
'CM3',
'CM4',
'CM5',
'CM6',
'CM11',
'CM12',
'CM15',
'TN1',
'TN2',
'TN3',
'TN4',
'TN5',
'TN6',
'TN7',
'TN8',
'TN9',
'TN10',
'TN11',
'TN12',
'CT14',
'CT15',
'CT16',
'CT17',
'CT18',
'CT19',
'CT20',
'D01',
'D02',
'D03',
'D04',
'D05',
'D06',
'D07',
'D08',
'D09',
'D11',
'D12',
'D6W'
@columns
这会逐行读取输入,使用单个制表符作为分隔符分割每一行,并构造一个从每行的非空列调用的数组数组,这些列由单引号(八进制\047
)包围。
当整个文件被读取后,它会使用map
“展平”(即转换为单个数组)并在,\n
每个元素之间打印它。
BTW,map
是一个内置的 perl 函数,用于对列表/数组执行操作。它可以被认为是一个奇特的专门for
循环。perldoc -f map
详情请参阅。perldoc -f split
如果您不熟悉 perl 的split
函数,阅读也会很有用。还有perldoc -f join
。