次のようなテキストがたくさんあります。
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
入力にタブ区切りのフィールドがある行があり、まず上から下に各行の最初のフィールドが必要で、2番目のフィールドなどが必要で、引用符とコンマが必要であると仮定すると、次のような安価なソリューションがあります。
最大9つの列を持つ2つの見苦しい行(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でテストされており、最初の2つは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 -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
これは入力を1行ずつ読み、単一のタブ文字を区切り文字として各行を分割し、一重引用符(8進数)で囲まれた各行のnull以外の列から呼び出される配列の配列を構成します\047
。
ファイル全体を読み取るときは、map
「平坦化」(つまり、単一の配列に変換)を使用し、各,\n
要素間に印刷します。
ちなみに、map
リスト/配列の操作を実行するための組み込みPerl関数です。珍しい特殊for
ループだと思います。perldoc -f map
詳細より。perldoc -f split
Perlの機能に慣れていない場合でも読んでみるとsplit
便利です。しかもperldoc -f join
。