구분 기호가 쉼표인 데이터 파일에서 "" 사이의 데이터를 추출하고 싶습니다.
입력 파일 예:
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10,000",8/13/2019,
예상 출력:
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10000",8/13/2019,
답변1
이것이 올바른 형식의 CSV라고 가정하면(예제 데이터는 이 점에서 괜찮아 보입니다) csvformat
다음에서 사용할 수 있습니다.csvkit
필드 구분 기호를 데이터에 없는 다른 문자로 일시적으로 변경합니다. 예를 들어 @
모든 쉼표를 제거한 다음 필드 구분 기호를 다시 기본값으로 변경합니다.
$ csvformat -D '@' file.csv | tr -d , | csvformat -d '@'
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,10000,8/13/2019,
출력에는 수정한 필드 주위에 따옴표가 없지만 더 이상 필요하지 않기 때문입니다.
분명히 "모든 쉼표 제거"는 실제로 제거하고 싶지 않은 쉼표를 제거할 수 있으므로 보다 선택적으로 7번째 필드의 쉼표만 제거할 수 있습니다.
$ csvformat -D '@' file.csv | awk -F '@' 'BEGIN { OFS=FS } { gsub(",", "", $7); print }' | csvformat -d '@'
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,10000,8/13/2019,
답변2
또 다른 awk
해결책:
awk -F\" '{
OFS="\"";
for ( i = 1; i <= NF; i++ ) {
if ( i % 2 == 0 ) {
gsub(/,/, "", $i)
}
}
}1' input.csv
그러면 큰따옴표를 필드 구분 기호로 사용하고 모든 필드를 반복합니다. 필드 번호가 짝수인 경우(완전한 것은 아니지만 예제에서 필드가 따옴표 사이에 존재함을 의미해야 함) 필드에서 모든 쉼표가 제거됩니다. 이렇게 하면 출력 필드 구분 기호로 큰따옴표를 사용하여 모든 내용이 인쇄 1
됩니다 (변경됨).awk
사용 중:
$ cat input.csv
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10,000",8/13/2019,
,7/30/2019,7/31/2019,"100",FH/FN 30yr & 20yr TBA & Spec ,"10,000,000",8/13/2019,
,7/30/2019,7/31/2019,"Jack, Mary, and Jane",8/1/2019,"123,456,789,012,345,678","10,000",8/13/2019,
$ awk -F\" '{
> OFS="\"";
> for ( i = 1; i <= NF; i++ ) {
> if ( i % 2 == 0 ) {
> gsub(/,/, "", $i)
> }
> }
> }1' input.csv
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10000",8/13/2019,
,7/30/2019,7/31/2019,"100",FH/FN 30yr & 20yr TBA & Spec ,"10000000",8/13/2019,
,7/30/2019,7/31/2019,"Jack Mary and Jane",8/1/2019,"123456789012345678","10000",8/13/2019,
노트:이것~ 할 것이다숫자가 아닌 필드에서 쉼표를 제거합니다. csv 파일을 올바르게 읽으려면 이 작업을 수행해야 합니다. 어떤 이유로든 쉼표를 유지하려면 다음 해결 방법을 사용할 수 있습니다.
awk -F\" '{
OFS="\"";
for ( i = 1; i <= NF; i++ ) {
if ( i % 2 == 0 && $i ~ /[0-9]/ ) {
gsub(/,/, "", $i)
}
}
}1' input.csv
답변3
예를 들면 다음과 같습니다 awk
.
cat oldfile | awk '{ print gensub ("(,\"[0-9]+),([0-9][0-9][0-9]),?([0-9][0-9][0-9])?,?([0-9][0-9][0-9]),?","\\1\\2\\3\\4","g");}' > newfile
이는 대용량 데이터에도 적용됩니다.
설명하다:
awk
프로그래밍 가능한 필터입니다. 명령줄(바깥 작은따옴표 "'" 사이)에 지정된 명령은 파일의 각 입력 줄에 대해 실행됩니다.
awk 프로그램은 다음과 같습니다(다른 형식):
{
print gensub ("(,\"[0-9]+),([0-9][0-9][0-9]),?([0-9][0-9][0-9])?,?([0-9][0-9][0-9]),?",
"\\1\\2\\3\\4",
"g");
}
-buildin awk
명령은 gensub
첫 번째 인수에 제공된 내용을 두 번째 인수에 제공된 대체 항목으로 바꿉니다. 세 번째 인수가 "g" 또는 "G"로 시작하는 문자열인 경우 모든 항목을 대체합니다(더 이상 찾을 수 없을 때까지 시도).
대체되는 것은 무엇입니까? 첫 번째 인수는 큰따옴표로 묶인 정규식(qv)입니다. 다음 부분은 다음과 같습니다. ,\
그런 다음 [0-9]+
한 번 이상 반복되는 숫자 0-9를 나타냅니다(접미사 연산자 +
). ,
이는 단지 한 문자이고 그 뒤에 [0-9][0-9][0-9]
쉼표가 ,
뒤따르고 그 뒤에 질문이 옵니다. 표시 ?
(이제 첫 번째 부분이 무엇을 의미하는지 알지만 접미사는 ?
새로운 것입니다. 쉼표 숫자는 생략할 수 있습니다). 그런 다음 더 많은 숫자 그룹과 생략할 수 있는 쉼표가 있습니다. 이는 더 큰 숫자에 대한 것입니다.
이번 설명에서는 지금까지 괄호 (
를 생략했습니다 ! )
이는 표현과 일치하지만 기억되는 것을 표시합니다. 두 번째 인수에서는 첫 번째 부터 네 번째까지 일치하는 항목(숫자)을 gensub
인용 하고 거기에서 다시 인쇄합니다.\1
\4
답변4
sed '/\"/,/\"/s/,//'
제공한 주소 범위는 행 내의 범위가 아닌 행 범위만 필터링하기 때문에 시도가 실패합니다.
이러한 유형의 임무는 표준에서는 성가신 일입니다 sed
. 쉼표만 있으면 sed -E 's/("[0-9]*),([0-9]*")/\1 \2/
문제가 해결되지만 쉼표가 여러 개 있으면 반복해야 하므로 다음과 같은 추악한 결과가 나옵니다.
sed -Ee :loop -e 's/("[0-9 ]*),([^"]*")/\1 \2/;tloop'
여는 큰 따옴표 뒤에 임의의 자릿수가 따라오고 교체에 인용되어 있으며 ("[0-9]*)
쉼표 뒤의 모든 항목과 끝까지 일치하므로 동일하지만 첫 번째 쉼표를 대체합니다.\1
([^"]*")
"
\1 \2
이제 교체가 이루어지면 t
명령이 태그로 분기됩니다. loop
더 이상 바꿀 쉼표가 없을 때까지 이를 반복합니다.
이는 여러 숫자와 원하는 만큼의 쉼표 ,7/30/2019,"99,999,999,999,999",0,1 ,"10,000","foo, bar"
로 도 작동합니다.,7/30/2019,"99 999 999 999 999" 0 1 "10 000" "foo, bar"