각 필드가 쉼표로 구분된 아래와 같은 파일이 있습니다. 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)"""