다음과 같은 행이 많은 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,,,
...
내가 해야 할 일은 다섯 번째 열이 (
세 번째 열 대신 대괄호 사이의 값을 복사하여 시작하는 경우입니다. 그렇지 않은 경우 해당 줄을 그대로 두십시오.
결과는 다음과 같습니다.
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
왜 파이썬을 사용하지 않습니까? (파일 이름을 파일 이름으로 바꾸십시오)
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
다른 버전은 작동하지만 제가 하고 있는 작업 흐름에는 맞지 않습니다.
감사해요!