텍스트 파일에서 따옴표 사이의 단일 또는 두 개의 공백을 바꾸는 방법

텍스트 파일에서 따옴표 사이의 단일 또는 두 개의 공백을 바꾸는 방법

일부 필드가 따옴표로 묶인 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}'

즉, 레코드 구분 기호는 "짝수 레코드에서만 문자와 공백을 대체합니다.

RTGNU 특정 부분입니다.

GNU와 동일 sed:

tr '\n"' '"\n' | sed -E '2~2s/ +/,/g' | tr '"\n' '\n"'

휴대성이 향상되었습니다.

tr '\n"' '"\n' | sed 'n;s/  */,/g' | tr '"\n' '\n"'

다른 seds와 함께 사용할 수 있지만 입력한 마지막 문자가 가 아닌 경우 문제가 발생할 수 있습니다 ".

관련 정보