awk를 사용하여 큰따옴표 바꾸기

awk를 사용하여 큰따옴표 바꾸기

각 필드가 쉼표로 구분된 아래와 같은 파일이 있습니다. 5번째 필드( "txt4 "(tst)"") 를 변경 하고 "두 개의 바깥쪽 따옴표를 제외하고 해당 필드의 모든 항목을 로 바꿔야 합니다 chr(34). 즉, 마지막 필드는 으로 변환되어야 합니다 "txt4 chr(34)(tst)chr(34)". 실제 데이터에는 여기에 표시된 것보다 더 많은 필드가 포함될 수 있으므로 솔루션의 특정 필드를 나열하는 것은 비현실적입니다.

아래 표시된 출력을 얻으려면 awk를 사용해야 합니다.

샘플 csv 파일:

"this is txt1","this is txt2",3,"this txt3","txt4 "(tst)"" 

원하는 출력:

"this is txt1","this is txt2",3,"this txt3","txt4 chr(34)(tst)chr(34)"

답변1

데이터의 소스 또는 예상 형식에 대해 실제로 많이 말하지 않습니다. 연습을 "replace with "(" 또는 "replace with"로 재구성할 수 있는 경우 다음 두 명령을 사용하면 됩니다.chr(34)("))chr(34)"(tst)"chr(34)(tst)chr(23)sed

$ sed -e 's/"(/chr(34)(/' -e 's/)"/)chr(34)/' file
"this is txt1","this is txt2",3,"this txt3","txt4 chr(34)(tst)chr(34)"
$ sed 's/"\((tst)\)"/chr(34)\1chr(34)/' file
"this is txt1","this is txt2",3,"this txt3","txt4 chr(34)(tst)chr(34)"

마지막 필드의 형식이 잘못되어 텍스트를 CSV 레코드로 구문 분석할 수 없습니다. 이 필드의 올바르게 인용된 버전은 다음과 같습니다 "txt4 ""(tst)""".

답변2

여기서 우리는 유효한 CSV 필드 따옴표가 줄의 시작 부분, 줄 끝 또는 쉼표 옆에 있다는 것을 알 수 있습니다. 따라서 각 인용문과 그 양쪽에 있는 문자를 검색하세요. 둘 다 쉼표가 아니면 따옴표가 두 배가 됩니다.

이것은 절대적으로 사실이 아닙니다. 유효한 CSV에서는 따옴표 안에 쉼표가 포함될 수 있습니다(예: "one field", "here"). 하지만 이는 귀하의 데이터에 적용됩니다.

시험:

Paul--) ./awkFixCsv

"this is txt1","this is txt2",3,"this txt3","txt4 "(tst)"" <<< Input
"this is txt1","this is txt2",3,"this txt3","txt4 ""(tst)""" <<< Output

"this is txt1","this is txt2",3,"this txt3","txt4 "(tst)"",""","""","done" <<< Input
"this is txt1","this is txt2",3,"this txt3","txt4 ""(tst)""","""","""""","done" <<< Output

One,Two,"3","Four","Five "and" Six",Seven and Eight,"Nine" <<< Input
One,Two,"3","Four","Five ""and"" Six",Seven and Eight,"Nine" <<< Output
Paul--) 

코드, 테스트 데이터를 여기에 문서화하고 함수로 수정합니다. 이것을 스크립트에 통합하는 방법을 모른다면 댓글을 남겨주세요.

#! /bin/bash

AWK='

function Fix (s, Local, t, u, x) {
    while (match (s, ".\042.")) {
        u = substr (s, RSTART, RLENGTH);
        x = (u ~ /..,/ || u ~ /,../) ? 0 : 1;
        t = t substr (s, 1, RSTART + x); 
        s = substr (s, RSTART + 1); 
    }
    return (t s);
}

{ print "\n" $0 " <<< Input"; }
{ $0 = Fix( $0); }
{ print $0 " <<< Output"; }
'
    awk "${AWK}" <<[][]
"this is txt1","this is txt2",3,"this txt3","txt4 "(tst)""
"this is txt1","this is txt2",3,"this txt3","txt4 "(tst)"",""","""","done"
One,Two,"3","Four","Five "and" Six",Seven and Eight,"Nine"
[][]

답변3

진주의텍스트::CSV이 모듈은 이와 같은 잘못된 형식의 CSV를 처리하는 데 매우 능숙합니다. 특히:

CSV 데이터가 정말 나쁜 경우.

1,"foo "bar" baz",42 or

1,""foo bar baz"",42 

이 데이터 행을 구문 분석하고 인용된 필드 내에서 인용문을 그대로 유지하는 방법이 있습니까? 이는 Allow_loose_quotes를 설정하고 escape_char가 quote_char와 같지 않도록 하여 달성할 수 있습니다.

예를 들어

$ echo '"this is txt1","this is txt2",3,"this txt3","txt4 "(tst)""' | perl -MText::CSV -lne '
  BEGIN{$p = Text::CSV->new({escape_char => "", allow_loose_quotes => 1, quote_space => 1})} 
  @row = $p->fields() if $p->parse($_); 
  $p->escape_char("\""); $p->print(*STDOUT,\@row);
'
"this is txt1","this is txt2",3,"this txt3","txt4 ""(tst)"""

관련 정보