쉼표()로 구분된 입력 파일이 있습니다 ,
. 일부 필드는 쉼표와 함께 큰따옴표로 묶여 있습니다. 샘플라인입니다
123,"ABC, DEV 23",345,534.202,NAME
큰따옴표뿐만 아니라 큰따옴표 안에 있는 모든 쉼표를 제거해야 합니다. 따라서 위 줄은 다음과 같이 구문 분석되어야 합니다.
123,ABC DEV 23,345,534.202,NAME
다음 사용법을 시도했지만 sed
예상한 결과를 얻지 못했습니다.
sed -e 's/\(".*\),\(".*\)/\1 \2/g'
sed
아니면 awk
다른 UNIX 유틸리티에 대한 빠른 팁이 있습니까?
답변1
awk
인용문이 균형을 이루면 다음과 같이 표현될 수 있는 인용문 사이의 쉼표를 제거해야 합니다.
awk -F'"' -v OFS='' '{ for (i=2; i<=NF; i+=2) gsub(",", "", $i) } 1' infile
산출:
123,ABC DEV 23,345,534.202,NAME
설명하다
큰 따옴표 문자로 필드 분할을 수행하도록 awk에 지시합니다 -F"
. 이는 다른 모든 필드가 따옴표로 묶인 텍스트임을 의미합니다. for 루프는 gsub
다른 모든 필드에서 작동합니다. 전역 대체의 약자로서 ","
쉼표( )를 빈( ""
)으로 바꿉니다. 마지막으로 1
기본 코드 블록을 호출합니다: { print $0 }
.
답변2
하나 있다좋아요응답, sed를 한 번만 사용하세요반지:
echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME'|
sed ':a;s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /;ta'
123,"ABC DEV 23",345,534,"some more comma-separated words",202,NAME
설명하다:
:a;
추가 지점에 대한 레이블입니다.s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /
3개의 닫힌 부품을 포함할 수 있습니다.- 첫 번째 두 번째:
[^"]*,\?\|"[^",]*",\?
큰따옴표를 포함하지 않고 뒤에 쉼표가 올 수도 있는 문자열과 일치합니다.또는쉼표 없이 두 개의 큰따옴표로 묶인 문자열이며 뒤에 쉼표가 올 수도 있습니다. - 첫 번째 것보다희토류 부분이전에 설명한 파트 2의 여러 반복으로 구성되며 그 뒤에 큰따옴표와 일부 문자가 따르지만 큰따옴표와 쉼표는 없습니다.
- 첫 번째 RE 부분 뒤에는 혼수상태가 옵니다.
- 나머지 줄은 건드릴 필요가 없습니다.
- 첫 번째 두 번째:
ta
:a
이전s/
명령이 일부 변경된 경우 반복됩니다.
루프가 완료되면 다음을 추가할 수도 있습니다 s/ */ /g
.
echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME'|
sed ':a;s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /;ta;s/ */ /g'
이중 공백을 억제합니다.
123,"ABC DEV 23",345,534,"some more comma-separated words",202,NAME
답변3
균형 잡힌 따옴표 사이의 여러 쉼표도 처리하는 일반적인 솔루션에는 중첩된 대체가 필요합니다. 나는 주어진 입력의 각 줄을 처리하고 다른 모든 따옴표 쌍의 쉼표만 바꾸는 솔루션을 Perl로 구현했습니다.
perl -pe 's/ " (.+? [^\\]) " # find all non escaped
# quoting pairs
# in a non-greedy way
/ ($ret = $1) =~ (s#,##g); # remove all commas within quotes
$ret # substitute the substitution :)
/gex'
아니면 간단히 말해서
perl -pe 's/"(.+?[^\\])"/($ret = $1) =~ (s#,##g); $ret/ge'
처리할 텍스트를 명령으로 파이프하거나 마지막 명령줄 인수로 처리할 텍스트 파일을 지정할 수 있습니다.
답변4
두 번째 참조가 잘못되었습니다.
sed -e 's/\(".*\),\(.*"\)/\1 \2/g'
또한 정규식을 사용하면 텍스트의 가능한 가장 긴 부분과 일치하는 경향이 있습니다. 즉, 문자열에 따옴표로 묶인 필드가 여러 개 있는 경우에는 이 방법이 작동하지 않습니다.
sed에서 여러 참조 필드를 처리하는 방법
sed -e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' -e 's/\"//g'
이는 이 문제를 해결하는 방법이기도 합니다. 그러나 참조된 각 필드에 여러 개의 쉼표가 포함될 수 있는 입력의 경우 sed의 첫 번째 표현식은 단일 필드의 최대 쉼표 내용만큼 또는 변경되지 않을 때까지 반복되어야 합니다. 출력이 전혀.
여러 표현식으로 sed를 실행하는 것은 여러 sed 프로세스를 실행하고 모든 "tr"을 개방형 파이프로 실행하는 것보다 더 효율적입니다.
그러나 입력 형식이 올바르지 않으면 바람직하지 않은 결과가 발생할 수 있습니다. 즉, 중첩된 따옴표, 끝나지 않은 따옴표입니다.
실행 예제 사용:
echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME' \
| sed -e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' \
-e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' -e 's/\"//g'
산출:
123,ABC DEV 23,345,534,some more comma-separated words,202,NAME