CSV 파일에서 큰따옴표로 묶인 숫자 안에 있는 쉼표만 제거하세요.

CSV 파일에서 큰따옴표로 묶인 숫자 안에 있는 쉼표만 제거하세요.

,텍스트 파일에서 (쉼표)와 (따옴표)도 제거하고 싶습니다 "(큰따옴표에 쉼표로 구분된 숫자가 포함된 경우에만).

56,72,"12,34,54",x,y,"foo,a,b,bar"

예상 출력

56,72,123454,x,y,"foo,a,b,bar"

메모:위의 줄을 예시로 보여드리겠습니다. 내 텍스트 파일에는 위와 같은 많은 줄이 포함되어 있으며 큰따옴표 안에 있는 쉼표로 구분된 숫자는 다양해야 합니다. 그건,

56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"

예상 출력:

56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

n큰따옴표 안에는 쉼표로 구분된 여러 숫자가 있습니다 . 그리고 문자가 포함된 큰따옴표도 그대로 둡니다.

나는 sed텍스트 처리 도구를 좋아합니다. sed이에 대한 해결책 을 게시해 주시면 기쁩니다 .

답변1

Perl이 괜찮다면 다음과 같은 짧은(반드시 단순하지는 않지만 아마도 빠를 것입니다 :)) 방법이 있습니다:

perl -pe 's:"(\d[\d,]+)":$1=~y/,//dr:eg' file

e연산자 에 대한 플래그 ( s:::를 작성하는 또 다른 방법임 s///)는 대체 항목이 매번 평가되는 표현식으로 처리되도록 합니다. 해당 표현식은 $1정규식(이미 따옴표가 누락됨)에서 캡처를 가져와 모든 쉼표를 삭제( )하여 변환( y///, 로 쓸 수도 있음 )을 변환합니다. 번역 횟수 대신 번역된 문자열 값을 얻으려면 플래그가 필요 합니다 .tr////dry

Perl로 인해 기분이 나빠지는 사람들을 위해 여기에 상응하는 Python이 있습니다. Python은 실제로 쉘 한 줄짜리 도구는 아니지만 때로는 협력하도록 유도될 수 있습니다. 다음은 (루프와 달리) 한 줄로 작성할 수 있지만 for가로 스크롤로 인해 읽을 수 없게 됩니다.

python -c '
import re;
import sys;
r=re.compile("\"(\d+(,\d+)*)\"");
all(not sys.stdout.write(r.sub(lambda m:m.group(1).replace(",",""),l))
    for l in sys.stdin)
' < file

답변2

이 (에서 적응여기) @rici의 Perl이 훨씬 간단하지만 필요한 작업을 수행해야 합니다.

$ sed -r ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;ta; s/""/","/g; 
          s/"([0-9]*)",?/\1,/g ' file
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454,
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

설명

  • :a: 라는 라벨을 정의합니다 a.
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/: 이건 분해해야 해
    • 우선, 이 구문을 사용하면 : (foo(bar)), \1will be foobar\2will be 입니다 bar.
    • "[0-9,]*",?: 0개 이상의 0-9or 와 일치하고 ,그 뒤에 0 또는 1 이 옵니다 ,.
    • ("[0-9,]*",?)*: 위 항목 중 0개 이상과 일치합니다.
    • "[0-9,]*: a 바로 다음에 오는 0개 이상의 0-9or 와 일치합니다.,"
  • ta;: 레이블로 돌아가서 a다시 실행만약에교체에 성공했습니다.
  • s/""/","/g;: 후처리. ""로 교체하세요 ",".
  • s/"([0-9]*)",?/\1,/g: 숫자 주위의 모든 따옴표를 제거합니다.

다른 예를 보면 더 쉽게 이해할 수 있습니다.

$ echo '"1,2,3,4"' | sed -nr ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;p;ta;'
"1,2,34"
"1,234"
"1234"
"1234"

따라서 따옴표 바로 뒤에 쉼표와 다른 숫자가 오는 숫자를 찾을 수 있지만 두 숫자를 함께 결합하고 더 이상 불가능할 때까지 프로세스를 반복하십시오.

info sed이 시점에서 위에서 사용된 레이블과 같은 고급 기능을 설명하는 섹션에 나오는 인용문을 언급하는 것이 유용하다고 생각합니다 (@Braiam을 찾아주셔서 감사합니다).

대부분의 경우 이러한 명령을 사용하면 `awk' 또는 Perl과 같은 프로그래밍을 사용하는 것이 더 나을 수도 있습니다.

답변3

CSV 데이터의 경우 실제 CSV 파서가 있는 언어를 사용하겠습니다. 예를 들어 Ruby의 경우:

ruby -rcsv -pe '
  row = CSV::parse_line($_).map {|e| e.delete!(",") if e =~ /^[\d,]+$/; e} 
  $_  = CSV::generate_line(row)
' <<END
56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"
END
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

답변4

사용라쿠(이전에는 Perl_6으로 알려짐)

~$ raku -pe 's:g/ \" ~ \" (\d+) ** 2..* % "," /{$0.join}/;'  file

샘플 입력:

56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"

샘플 출력:

56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

Raku는 여러 가지 강력한 정규식 기능을 갖춘 Perl 계열의 프로그래밍 언어입니다. 이 답변에 대한 일반적인 개요는 아래 URL을 참조하세요.

https://unix.stackexchange.com/a/722570/227738

위 코드에서는 숫자를 인식하고 삽입된 쉼표를 제거했습니다. 정규식은 다음과 같은 사실을 이용합니다.중첩 구조Raku의 새로운 ~ 물결표(중첩) 표기법으로 표시할 수 있습니다. 즉, \" ~ \" [\d+]"" 큰따옴표로 둘러싸인 하나 이상의 숫자"를 의미합니다.

추가적으로,반복되는 구조%반복 구조에 대한 Raku의 새로운 수정 수량자로 표시할 수 있습니다 . [\d+] ** 2..* % "," 표기는 " ,이 패턴이 ** 2..*두 번 이상 반복되고 쉼표로 구분된 하나 이상의 숫자를 의미합니다. [후행 구분 기호가 있는 경우(예: 쉼표), 구문] %%대신 에 a를 사용하세요.%

이것은 단지 시작일 뿐입니다. 대체 구분 기호, 삽입된 줄 바꿈, 삽입된 쉼표, 잠재적으로 공백인 필드 등이 있는 CSV 파일은 실제로 Raku Text::CSV모듈과 같은 진정한 CSV 파서로 처리되어야 합니다. 자세한 내용은 아래 링크를 참조하세요.

https://docs.raku.org/언어/regexes
https://raku.land/github:Tux/Text::CSV
https://raku.org

관련 정보