CSV 파일의 문자열 값에서 쉼표 처리하기

CSV 파일의 문자열 값에서 쉼표 처리하기

숫자 열과 문자열 열이 포함된 쉼표로 구분된 파일이 있습니다. 문자열 열은 따옴표로 묶여 있으며 따옴표 사이에 쉼표가 있을 수 있습니다. 열을 식별하는 방법은 무엇입니까 FS =","?

샘플 기록

"prabhat,kumar",19,2000,"bangalore,India"

존재하다AWK그것은해야한다

$1 = "prabhat,kumar"
$2 = 19
$3 = "2000"
$4 = "bangalore,india"

설정 FS=","으로 인해 문제가 발생합니다.

입력은 다음과 같습니다

"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"
"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"

출력은 다음과 같아야 합니다.

"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"
"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"

내가 시도하는 코드:

awk -F"," '{for(i=1;i<=NF;i++){if(i%NF==0){ORS="\n"} {if($i ~ /^\"/ || $i ~ /\"$/) {a=a OFS $i;j++;{if(j%2==0){sub(/^\,/,X,a); print a;j=0;a=""}}} else {print $i}}} {ORS="|"}}' ORS="|" OFS=, p.txt

답변1

먼저, 적합한 CSV 파서를 사용해야 합니다. 예를 들어 Perl에서는 다음을 사용할 수 있습니다 Text::CSV.

  1. 설치 cpanm(Perl을 사용한다면 나중에 감사할 것입니다)

    $ sudo apt-get install cpanminus
    

    Debian 기반 시스템을 사용하지 않는 경우 배포판의 패키지 관리자를 사용하여 설치할 수 있습니다.

  2. Text::CSV모듈 설치

    $ sudo cpanm Text::CSV
    
  3. 파일을 구문 분석

    $ perl -MText::CSV -le '
        $csv = Text::CSV->new({binary=>1}); 
        while ($row = $csv->getline(STDIN)){
        print "1:$row->[0], 2:$row->[1], 3:$row->[2], 4:$row->[3]"}' < file.csv 
    1:prabhat,kumar, 2:19, 3:2000, 4:bangalore,India
    

    위에서 볼 수 있듯이 첫 번째 필드는 $row->[0], 두 번째 필드 $row->[1]등입니다.


이것이 올바른 방법입니다. 더 간단하지만 지저분한 방법은 인용된 쉼표를 다른 문자로 바꾸는 것입니다. 그런 다음 정상적으로 사용 awk하고 마지막으로 다시 쉼표로 전환하십시오. 여기서는 이를 사용하고 있지만 ###필드 중 하나에 절대 나타나지 않을 것이라고 확신하는 모든 것을 사용할 수 있습니다.

$ sed -r 's/("[^",]+),([^",]+")/\1###\2/g' file.csv | 
    awk -F, '{print $1,$3}' | sed 's/###/,/g'
"prabhat,kumar" 2000

답변2

GNU가 있는 경우 awk:

$ awk -vFPAT='[^,]*|"[^"]*"' '{ gsub("^\"|\"$","",$1); gsub("^\"|\"$","",$4); print $1 $4} '
prabhat,kumarbangalore,India

$1출력 형식은 인쇄만 하고 나란히 있기 때문에 약간 보기 흉합니다 $4. 자신의 취향에 맞게 변경할 수 있다고 확신합니다.

필드 주위에 큰따옴표를 유지해야 하는 경우 이 두 gsub();함수를 제거하십시오.

설명하다:

일반적으로 awk레코드의 필드는 (FieldSeparator) 변수의 내용으로 구분되며 FS기본값은 공백(탭, 공백 및 줄 바꿈)입니다. 구분 기호는 awk레코드가 끝나는 위치를 알려줍니다. 파일 에서 csv레코드는 쉼표로 끝나지만( awkas 로 전달됨 -vFS=,) 물론 귀하와 같은 예에서는 너무 간단하여 깨질 수 있습니다.

또는 FPAT(필드 패턴) 정의의 레코드입니다 awk. 레코드가 끝나는 위치를 지정하는 대신 awk전체 레코드를 포함하는 정의를 만듭니다. 귀하의 예가 복잡하기 때문에 csv이것은[^,]*|"[^"]*"

고장은 다음과 같습니다 : -

  • [^,]쉼표가 아닌 문자( *)를 최대한 많이 사용하세요. 두 쉼표 사이의 모든 내용은 필드입니다.
  • 또는( |)
  • 작은 큰따옴표( ") 뒤에 큰따옴표가 없는 경우( [^"]) 가능한 한 여러 번( *) 다음에 작은 큰따옴표( ")가 나옵니다. 쉼표를 포함하여 큰따옴표 안의 모든 항목은 하나의 필드로 계산됩니다.

답변3

Ruby는 CSV 구문 분석에 매우 편리합니다.

ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|")' file
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS

출력에는 따옴표가 없습니다. 이는 필드 구분 기호가 포함된 필드가 없기 때문입니다. 따옴표가 필요한 경우 모든 필드(정수 포함)를 강제로 따옴표로 묶을 수 있습니다.

ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|",:force_quotes=>true)' file
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"

답변4

이것은 나에게 효과적입니다.

$ echo '"prabhat,kumar",19,2000,"bangalore,India"' | 
  awk -F, '{print $1,$2,$3,$4,$5,$6}'| 
    awk -F\" '{print $2,$3,$4}'|awk -F\  '{print $1","$2,$3,$4,$5","$6}'`

관련 정보