명령줄을 통해 CSV 파일 처리: 두 번째 열 값이 동일한 경우 연속 행 항목 사이의 중간 행만 제거합니다.

명령줄을 통해 CSV 파일 처리: 두 번째 열 값이 동일한 경우 연속 행 항목 사이의 중간 행만 제거합니다.

열이 2개만 있는 CSV 파일이 있습니다(하지만위치행) 및 항상 별표(*) 문자로 시작하고 세 개 이상의 열에 걸쳐 있을 수 있는 가끔 불규칙한 행이 있습니다. Linux 명령줄만 사용하면 예상되는 동작은 다음과 같습니다.

  1. 3개 이상의 연속된 데이터 행이 두 번째 열 값이 동일한 경우 가운데 행을 삭제합니다. 시작선과 끝선을 유지하세요.
  2. 별표로 시작하는 불규칙한 선 유지

예를 들어 다음을 포함하는 CSV가 있는 경우:

    0,Apple
    1,Apple
    2,Apple
    * Checkpoint
    * Another checkpoint
    3,Apple
    4,Apple
    5,Box
    6,Box
    7,Citrus
    8,Box
    9,Apple
    10,Apple
    11,Apple
    12,Dove
    13,Citrus
    * Sudden checkpoint, * Leftover checkpoint note 1, * Leftover checkpoint note N
    14,Citrus
    15,Citrus
    16,Citrus
    17,Apple
    18,Citrus

그러면 다음과 같아야 합니다.

    0,Apple
    * Checkpoint
    * Another checkpoint
    4,Apple
    5,Box
    6,Box
    7,Citrus
    8,Box
    9,Apple
    11,Apple
    12,Dove
    13,Citrus
    * Sudden checkpoint, * Leftover checkpoint note 1, * Leftover checkpoint note N
    16,Citrus
    17,Apple
    18,Citrus

위 예에서는 1~3행, 10행, 14~15행이 삭제되었습니다.

어떤 답변이라도 미리 감사드립니다.

건배

답변1

사용 awk:

BEGIN { FS = "," }

/^[*]/ { print; next }

{
        if (NR > 1 && $2 == word) {
                tail = $0
                ++count
        } else {
                if (count) print tail
                word = $2; count = 0
                print
        }
}

END { if (count) print tail }

스크립트 awk는 무조건 로 시작하는 모든 줄을 인쇄합니다 *. 행이 그러한 행이 아니고 두 번째 필드의 단어가 우리가 기억하는 단어인 경우 해당 레코드를 변수 tail(동일한 단어가 포함된 일련의 레코드의 마지막 레코드와 같은 "꼬리")에 저장합니다. 필드).

두 번째 필드가 다음과 같은 경우아니요이전과 동일하고 tail 레코드를 인쇄합니다. 이전 실행의 레코드가 여러 개인 경우 새 단어를 기억하고 동일한 단어의 두 번째 필드에 현재 레코드(새 실행의 하나 이상의 레코드 중 첫 번째 레코드)를 인쇄합니다. ).

제공된 데이터에 대해 테스트하고 다음과 같다고 가정합니다.간단한 CSV(임베디드 구분 기호나 개행 문자 등이 없음을 의미):

$ awk -f script file
0,Apple
* Checkpoint
* Another checkpoint
4,Apple
5,Box
6,Box
7,Citrus
8,Box
9,Apple
11,Apple
12,Dove
13,Citrus
* Sudden checkpoint, * Leftover checkpoint note 1, * Leftover checkpoint note N
16,Citrus
17,Apple
18,Citrus

위와 유사하지만 사용밀러( mlr), 이는 CSV를 지원하고 복잡한 인용 문자열이 포함된 CSV 레코드를 처리할 수 있습니다.

if (is_not_null(@word) && $2 == @word) {
        @tail = $*;
        false # omit this record for now
} else {
        is_not_null(@tail) {
                emit @tail # emit the tail record
        }
        @word = $2; @tail = null;
        true  # emit this record
}

end { is_not_null(@tail) { emit @tail } }

filterawk이는 위의 코드와 매우 유사한 논리를 사용하여 입력 데이터 세트의 레코드를 포함하거나 생략하는 Miller 하위 명령에 대한 표현식입니다 . Miller가 이 문자로 시작하는 줄을 탐색하도록 명령줄에서 use를 *사용할 수 있습니다 . 입력을 헤더 없는 CSV로 처리하려면 with를 --pass-comments-with='*'사용하세요 .--csv-N

$ mlr --pass-comments-with='*' --csv -N filter -f script file
0,Apple
* Checkpoint
* Another checkpoint
4,Apple
5,Box
6,Box
7,Citrus
8,Box
9,Apple
11,Apple
12,Dove
13,Citrus
* Sudden checkpoint," * Leftover checkpoint note 1"," * Leftover checkpoint note N"
16,Citrus
17,Apple
18,Citrus

관련 정보