값이 목록에 없으면 CSV에서 값을 제거합니다.

값이 목록에 없으면 CSV에서 값을 제거합니다.

100개의 행과 숫자 열이 포함된 CSV 테이블이 있습니다. 테이블의 일부 숫자가 포함된 1열 파일인 또 다른 목록이 있습니다. 목록에 없는 CSV의 모든 값을 제거하는 방법이 있나요?

이걸 목록 파일로 쓸 수 있을 줄 알았는데 grep -f, 제거하고 싶은 값 중 일부가 유지하고 싶은 값과 같은 행에 있어서 고민 중입니다.

예를 들어

CSV 테이블:

11,12,13 
11,10,12,13 

목록 파일:

13
11

산출:

11,,13 
11,,,,13 

또는 대안적으로

11,13 
11,13 

답변1

다음 awk절차에서는 CSV 필드에 선행 또는 후행 공백이 없다고 가정합니다.

awk 'BEGIN {FS=OFS=","}
     NR==FNR{valid[$1];next}
     {for (i=1;i<=NF;i++) {if (!($i in valid)) {$i=""}}} 1' validvalues.txt input.csv 

validvalues.txt유효한 값이 포함된 파일을 먼저 처리 한 다음 실제 CSV 파일을 처리합니다 .

  • BEGIN섹션 에서 입력 및 출력에 대한 필드 구분 기호가 로 설정됩니다 ,.
  • 첫 번째 파일( 파일별 NR​​라인 카운터와 동일한 글로벌 라인 FNR카운터로 표시됨)을 처리할 때 허용되는 값을 배열의 인덱스로 기록하고 valid, 그렇지 않으면 다음 입력 라인으로 처리를 건너뜁니다.
  • 두 번째 파일을 처리할 때 모든 필드를 반복하고 필드 내용이 "배열 인덱스"의 일부인지 확인합니다 valid. 그렇지 않은 경우 필드 값을 빈 필드로 설정합니다.
  • 1지금까지의 모든 수정 사항을 포함하여 현재 행의 겉보기에는 지저분해 보이는 인쇄입니다.

중요한 점은 ($i in valid)테스트가 문자열 기반 비교이므로 유효한 값 파일의 열 항목이나 CSV 파일의 필드에 선행/후행 공백이 포함되어 있는 경우 비교를 위해서는 동일한 공백이 예상치 못한 동작이 발생할 수 있습니다.

@glenn jackman이 언급했듯이절차는 다음과 같이 단순화될 수 있습니다.

awk 'BEGIN {FS=OFS=","}
     NR==FNR{valid[$1]=$1;next}
     {for (i=1;i<=NF;i++) {$i=valid[$i]}} 1' validvalues.txt input.csv 

여기서는 실제로 유효한 값을 "배열 값"으로도 등록합니다. 유효하지 않은 값은 에 항목이 없기 valid때문에 valid[$i]자동으로 빈 문자열로 평가되는 반면 유효한 값의 경우 값 자체를 반환한다는 아이디어입니다 .

그러나 "필드 값 자체"를 불필요하게 대체하고 더 많은 메모리를 필요로 하기 때문에 성능이 약간 느려지므로 "유효한 값" 파일이 큰 경우 문제가 될 수 있습니다.

답변2

다중 문자 RS 및 RT에 대한 GNU awk가 있는 경우:

$ awk -v RS='[,\n]' 'NR==FNR{a[$0]; next} {ORS=RT} $0 in a' list file.csv
11,13
11,13

답변3

원하지 않는 값의 파이프로 구분된 목록을 만들 수 있습니다.

list=$(<list.txt tr '\n' '|')

당신은 할 것 13|11|.

그런 다음밀러검색 및 바꾸기

mlr --nidx --fs "," -S put 'for (k in $*) {if($[k]!=~"^('"$list"')$"){$[k] = gsub($[k], $[k], "")}}' input.csv

가지다

11,,13
11,,,13

관련 정보