次の行が多いCSVファイルがあります。
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,L0480,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,L0481,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,L0487,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
...
私がしなければならないのは、5番目の列が(
3番目の列ではなく角括弧の間の値をコピーすることから始まる場合です。そうでない場合は、その行をそのままにしてください。
結果は次のとおりです。
1003,CC,LB1,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
...
これをやろうとしていますが、sed
括弧の間の部分をキャプチャできることはわかりますが、不明なテキストを変更する方法がわかりません。
これに使用できますかsed
?
答え1
CSVに含まれる区切り文字(引用符で囲まれたカンマを含むカンマ区切りフィールド)がないと仮定すると、Awkを使用するのは簡単です。
$ awk 'BEGIN{OFS=FS=","} match($5,/^\([0-9]+\)/) {$3 = substr($5,RSTART+1,RLENGTH-2)} 1' file.csv
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
Sedの使用(同じ制限あり):
$ sed -E 's/^([^,]*),([^,]*),([^,]*),([^,]*),\(([0-9]+)\)/\1,\2,\5,\4,(\5)/' file.csv
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
より強力には、PerlのText :: CSVモジュールを使用してください。
$ perl -C -MText::CSV -lne '
BEGIN{$p = Text::CSV->new()}
@f = $p->fields() if $p->parse($_);
$f[2] = $1 if $f[4] =~ /^\((\d+)\)/;
print join ",", @f
' file.csv
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
答え2
なぜPythonを使用しないのですか? (ファイル名をファイル名に変更)
import re, csv
for line in list(csv.reader(open('filename', 'r'))):
matches = re.findall('\([0-9]*\)',line[4])
if matches:
line[2] = matches[0]
print(','.join(line))
答え3
次のスクリプトで完了
count=`awk '{print NR}' filename| sort -nr| sed -n '1p'`
for ((i=1;i<=$count;i++)); do h=`awk -v i="$count" -F "," 'NR==i && $5 ~ /^\(/{print $5}' filename | awk '{print $1}'| sed -e "s/(//g" -e "s/)//g"| wc -l`; if [[ $h != 0 ]]; then k=`awk -v i="$count" -F "," 'NR==i && $5 ~ /^\(/{print $5}' filename | awk '{print $1}'| sed -e "s/(//g" -e "s/)//g"`; awk -v i="$count" -v k="$k" -F "," 'NR==i && $5 ~ /^\(/{$3=k;print $0}' filename| sed "s/ /,/g"; else awk -v i="$count" 'NR==i {print $0}' filename; fi; done
出力
1003,CC,LB1,,(LB1),Urbà,de,Barberà,del,Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781),St.,Vicenç,Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784),Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783),Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
答え4
awk
とsed
バージョンスチールドライバー提案された仕事は本当に魅力的で、現在の環境で実装するのはとても簡単でした。
角かっこの間のコードに文字、スペース、ドットを許可するように少し改善しました。
awk 'BEGIN{OFS=FS=","} match($5,/^\([a-zA-Z0-9 .]+\)/) {$3 = substr($5,RSTART+1,RLENGTH-2)} 1' file.csv
sed -E 's/^([^,]*),([^,]*),([^,]*),([^,]*),\(([a-zA-Z0-9 .]+)\)/\1,\2,\5,\4,(\5)/' file.csv
他のバージョンは動作しますが、私がやっているワークフローには合いません。
ありがとうございます!