일부 필드가 따옴표로 묶인 CSV 파일이 있는데 따옴표 안의 항목이 이중 공백 또는 단일 공백으로 구분되어 있습니다. 쉼표로 바꿔야 해요.
예시 라인:
This is okay,"ABC DEF GHI",123,"This is not okay",remove,spaces,within,quotes
그리고 그것은 어떻게 보여야 할까요:
This is okay,"ABC,DEF,GHI",123,"This,is,not,okay",remove,spaces,within,quotes
답변1
perl -pe 's/".*?"/do{$a = $&; $a =~ s: +:,:g; $a}/ge;'
본질적으로 이것은 단지 전역 정규식 대체입니다 s/regex/replacement/g
. 정규식은 ".*?"
다음으로 시작하고 끝나는 모든 하위 문자열과 일치한다는 것입니다. 까다로운 부분은 다음과 같습니다."
"
- 대체되는 것은 문자열이 아니라 계산된 표현식입니다. (이것이
e
다음 수정자의 의미입니다g
.) s:regex:replacement:g
평가된 표현식은 비어 있지 않은 공백 시퀀스를 쉼표로 바꾸는 전역 정규 표현식 대체입니다 . (외부 대체와 동일한 구분 기호를 사용할 수 없으므로:
대신 를 사용합니다/
.)- 내부 정규식 대체를 수행하려면 외부 대체의 일치하는 하위 문자열을
$&
다른 변수에 할당한$a
다음 내부 대체를 수행$a
하고 마지막으로 인쇄해야 합니다$a
.
완전히 새로운 버전의 Perl을 사용하면 보조 변수에 대한 할당을 피할 수 있습니다. 수정자를 사용하면 r
일치하는 하위 문자열의 복사본에서 직접 내부 교체를 수행할 수 있습니다 $&
(Stéphane Chazelas 덕분에):
perl -pe 's/".*?"/$&=~s: +:,:gr/ge;'
답변2
이 무차별 대입 솔루션을 고려하십시오.
awk -F, -v OFS=, '
{
for(i=1;i<=NF;i++)
if ($i ~ /^".*"$/)
gsub(" +", ",", $i)
print $0
}'
awk에게 레코드를 쉼표로 분할하라고 지시합니다. 필드에 쉼표가 포함되어 있으면 이것이 깨질 수 있다는 점에 유의하세요! -- 그리고 OFS를 사용하여 인쇄 문에 필드를 쉼표로 다시 그룹화하도록 지시합니다. for
줄의 각 필드를 반복 하며, 필드가 ^
큰따옴표로 시작하고 모든 문자를 포함하며 .*
큰 $
따옴표로 끝나면 $i
전역적으로 필드의 모든 공백을 쉼표로 바꿉니다. 필드를 반복한 후 전체 레코드를 인쇄합니다( $0
).
답변3
GNU 사용 awk
:
gawk -v RS=\" '
NR % 2 == 0{gsub(/ +/, ",")}
{ORS = RT; print}'
즉, 레코드 구분 기호는 "
짝수 레코드에서만 문자와 공백을 대체합니다.
RT
GNU 특정 부분입니다.
GNU와 동일 sed
:
tr '\n"' '"\n' | sed -E '2~2s/ +/,/g' | tr '"\n' '\n"'
휴대성이 향상되었습니다.
tr '\n"' '"\n' | sed 'n;s/ */,/g' | tr '"\n' '\n"'
다른 sed
s와 함께 사용할 수 있지만 입력한 마지막 문자가 가 아닌 경우 문제가 발생할 수 있습니다 "
.