csv로 변환된 Excel 파일이 있습니다. 변환 후에는 아래 예와 같습니다(csv에는 100개가 넘는 열이 있습니다. 이는 축소된 버전입니다).
,Product," ",Citty," ",Price
,Name," ",Location," ",Per Unit
,banana," ",CA," ",5.7
,apple," ",FL," ",2.3
첫 번째와 두 번째 줄을 가져와서 쉼표 배치에 따라 "병합"하는 스크립트를 작성해야 합니다.
,Product Name," "" ",Citty Location," "" ",Price Per Unit
,banana," ",CA," ",5.7
,apple," ",FL," ",2.3
여기와 Stack Overflow에서 다른 질문을 살펴봤지만 답변은 파일의 처음 두 행에 대한 이상한 열별 상황과 관련이 없는 것 같습니다.
관련 없는 추가 작업으로 csv에서 빈 열을 제거하고 오타를 수정하여 다음과 같이 보이도록 하고 싶습니다.
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
(csv에는 현재 각 실제 데이터 열 사이에 따옴표로 둘러싸인 탭이 있습니다. 단, 첫 번째 열은 비어 있고 뒤에 쉼표가 있습니다.)
여러 번 오타가 있는 CSV를 받게 되므로 스크립트의 오류를 프로그래밍 방식으로 수정하고 싶습니다. 또한 열이 항상 위에 표시된 순서대로 표시되지 않을 수 있으므로 스크립트 중에 각 열 이름에 오류가 있는지 동적으로 확인해야 합니다.
답변1
이 시도
$ awk -F, 'NR<2{split(gensub(/Citty/,"City","g",$0),a,FS)}NR==2{for(b=2;b<=NF;b+=2){c=c a[b]" "$b","}print gensub(/,$/,"",1,c)}NR>2{print gensub(/(^,|" *",)/,"","g",$0)}' inp
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
$
동일한 코드를 여러 줄로 나누면 더 읽기 쉽습니다.
$ awk -F, '
> NR<2{split(gensub(/Citty/,"City","g",$0),a,FS)}
> NR==2{for(b=2;b<=NF;b+=2){c=c a[b]" "$b","}print gensub(/,$/,"",1,c)}
> NR>2{print gensub(/(^,|" *",)/,"","g",$0)}' inp
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
$
첫 번째 행인 경우 행을 a 내의 배열 요소로 분할합니다. 도시->도시 철자 오류를 수정했습니다.
두 번째 행인 경우 두 번째 열부터 시작하여 해당 열과 함께 첫 번째 행의 해당 열을 인쇄합니다. 각 열에 대해 이 작업을 2열씩 반복합니다. 후행 항목을 제거하십시오 ,
.
두 번째 줄 이후에는 ,
선행 항목이나 모든 항목을 "<spaces>",
빈 문자열로 바꾸고 결과를 인쇄합니다.
GNU Awk 4.0.2에서 잘 테스트되었습니다.
답변2
Perl, Text::CSV 및 MoreUtils 사용:
perl -MText::CSV -MList::MoreUtils=pairwise -lne '
BEGIN { $p = Text::CSV->new(); }
@f = $p->fields() if $p->parse($_);
@hdr = map { s/Citty/City/ ; $_ } @f if $. == 1;
@f = pairwise { $a . " " . $b } @hdr, @f if $. == 2;
print join ",", grep { /\w/ } @f if $. > 1;
' file.csv
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
grep
단어 문자가 하나도 포함되지 않은 필드는 무시합니다 .
Perl >= 5.14.0을 사용하면 대체를 단순화하여 사용할 수 있습니다 map s/Citty/City/r @f
.무손실 교체수정자.
답변3
노력하다
awk -F, '
{gsub (/,*"[ ]*",*/, ",")
sub (/^,/, "")
sub (/Citty/, "City")
}
NR == 1 {n = split ($0, T)
next
}
NR == 2 {for (;n; n--) $n = T[n] " " $n
}
1
' OFS=, file
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3