vim을 사용하여 json에서 큰 청크 제거

vim을 사용하여 json에서 큰 청크 제거

나는 거대한 json 파일(50만 줄)을 가지고 있습니다.

특정 문자열이 포함된 항목 집합을 삭제해야 합니다.

{
    "bla1": {
        "Part1": "Plop1",
        "Part2": "Plop2",
        "Part3": "BadFling1<stuff>",
        "part4": "Plop4",
    },
    "bla2": {
        "Part1": "Plop1",
        "Part2": "Plop2",
        "Part3": "<stuff>",
        "part4": "Plop4",
    },
    // etc for many more entries
}

모든 항목에는 "Part3" 항목 앞에 "BadFling1"이 붙습니다.

"BadFling1"이 포함된 모든 항목을 자동으로 삭제하는 가장 좋은 방법을 알고 싶습니다. 예를 들어 위에서 잘못된 항목을 제거한 결과는 다음과 같습니다.

{
    "bla2": {
        "Part1": "Plop1",
        "Part2": "Plop2",
        "Part3": "<stuff>",
        "part4": "Plop4",
    },
    // etc for many more entries
}

첫 번째 시도는 성공했지만 충분히 빠르지 않았습니다(약간의 수동 작업이었기 때문에).

/BadFling1
qan3k5ddq
:map z n@a

이제 "z" 키를 누르고 있습니다.

내 vim foo가 충분히 강력하지 않아서 vim에서 프로세스를 더 잘 자동화하는 방법을 잘 모르겠습니다. 도움을 주시면 감사하겠습니다.

Bash의 대안(다른 명령줄 도구도 환영합니다).

답변1

이 시도 vim:

:g/BadFling/normal [{V]}d

그러면 :global패턴과 일치하는 모든 줄에서 명령이 실행됩니다( BadFling예로 사용했습니다. 필요한 경우 조정합니다). 이 경우 실행되는 명령은 :normal일반 모드 명령을 실행하는 명령과 동일합니다. 이것의 목적은 대괄호 쌍 사이의 이동 및 이동 명령 기능을 활용하는 것입니다 [{. is ]} vim조합은 Vd한 줄씩 삭제하는 데 사용됩니다. 이는 JSON 파서만큼 강력하지는 않지만 각 "blah1"섹션이 자체 행 집합에 포함되어 있다고 가정할 수 있으므로 행별로 삭제해도 실수로 다른 블록에 속한 항목이 삭제되지는 않습니다. 예를 들어 다음과 같은 경우에는 한 줄씩 삭제하는 방법이 작동하지 않습니다.

    ... end of block you want to keep
}, "blah1" : {
    block you want removed
}, "blah2" : {
    start of block you want to keep ...
}

또한 [{직접 상위 블록만 사용하므로 더 많은 중첩 수준이 있으면 작동하지 않습니다.

답변2

귀하의 버전이 충분히 새로운 경우 grep다음을 사용하여 수행할 수 있습니다.diffdiff

ire@localhost$ grep -B 3 -A 2 BadFling1 huge.json | diff --changed-group-format="%>" --unchanged-group-format="" - huge.json 
{
    "bla2": {
        "Part1": "Plop1",
        "Part2": "Plop2",
        "Part3": "<stuff>",
        "part4": "Plop4",
    },
    // etc for many more entries
}

grep일치하는 항목 주변의 행을 추출하여 잘못된 기록을 제거합니다. diff원본 버전에서 해당 항목을 제거하세요 . 설명에서 언급했듯이 이 솔루션을 사용하려면 블록 크기가 일관되고 일치하는 줄이 각 블록 내에서 동일한 위치에 있어야 합니다(예제에서와 같이).

그렇지 않은 경우(레코드의 크기가 다르거나 레코드 요소의 위치를 ​​신뢰할 수 없는 경우) 빠른 구문 분석 스크립트를 작성하기 위한 힌트로 삼겠습니다. JSON 파서가 내장된 Python 몇 줄만 사용하면 이러한 레코드를 쉽고 안전하게 삭제할 수 있습니다.

답변3

awk의 솔루션은 다음과 같습니다.

awk '/".*":\ {/             { open=line; skip_block=0 }
     /"Part3":\ "BadFling1/ { skip_block=1 }
     /},/                   { if (skip_block) { line=open; next } }
     { lines[line++]=$0 }
     END { for (i=0;i<=line;i++) { print lines[i] } }' yourfile > clean

아직 제대로 테스트되지 않았지만 시작하는 데 도움이 될 것입니다. 블록의 길이가 가변적이라 하더라도 작동하며, 블록 내에서 규정되지 않은 행이 어디에 있는지는 중요하지 않습니다.

설명하다:

1행: 이 행이 블록의 시작 부분과 일치하면 배열의 위치를 ​​기록하여 지금까지의 블록을 양호한 것으로 표시합니다.

2행: 이 행이 규정되지 않은 행과 일치하는 경우 블록을 표시합니다.

3행: 매치 블록의 끝입니다. 블록이 표시되면 배열의 위치를 ​​블록이 시작되는 위치로 재설정하고 다음 줄로 점프합니다.

4행 : 현재 행을 배열에 추가하고 행 카운터를 증가시킵니다.

5행: 파일을 읽은 후 "양호한" 블록만 포함된 배열을 인쇄합니다.

Bash에서도 동일한 기능을 얻을 수 있지만 awk가 훨씬 더 빠를 것입니다. 제 생각에는 "더 무거운" 언어를 사용하지 않고도 이것이 바로 awk의 목적입니다.

답변4

정력 사용:

:%s/BadFling1//g

"BadFling1"이 검색되면 모두 ""로 대체됩니다.

관련 정보