vim 정규식 검색 및 바꾸기

vim 정규식 검색 및 바꾸기

파일의 문자열 일부를 바꾸려고 합니다.

예를 들어 csv 파일이 있습니다.

r1,col1,col2,35,000,col4,col5
r2,col1,col2,1,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4,325.33,col4,col5

본질적으로 위의 col3을 교체하고 싶습니다. 또한 다음과 같이 첫 번째 x 숫자를 유지하십시오.

r1,col1,col2,35000,col4,col5
r2,col1,col2,1000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4325.33,col4,col5

보통 나는 처형을 할 것이다.

:%s/\,[0-9]*\,/\,\1/g

하지만 내가 달릴 때 나는 얻는다.

r1,col1,col2,000,col4,col5
r2,col1,col2,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,325.33,col4,col5

원하는 출력을 얻으려면 교체의 두 번째 부분에서 무엇을 사용해야 합니까?

답변1

가능한생각하다 :%s/\v(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/.

목표는 다른 곳에서 쉼표를 제거하거나 다른 텍스트를 제거하지 않고 네 번째 필드(있는 경우)에서 쉼표를 제거하는 것입니다. 복잡한 요소는 쉼표가 필드 구분 기호로도 사용된다는 것입니다. 이 문제를 해결하려면 필드 내에 쉼표가 나타날 수 있는 조건에 대한 지식을 고려해야 합니다. 결국, 더 이상의 제한이 없으면 귀하의 기록은 모호합니다.

두 자리에 걸쳐 있는 쉼표는 모두 제거될 것이라고 생각하기 쉽지만, 그렇지 않습니다. 귀하의 입력 예는 귀하가할 수 있는한 필드는 숫자로 끝나고 다음 필드는 col2,35,0001( )로 시작됩니다.

처음 세 개의 필드 자체에 쉼표가 포함되어 있지 않다는 것을 알면 문제가 훨씬 쉬워집니다. 쉼표를 제거하기 전에 쉼표가 뒤따르는 0개 이상의 쉼표가 아닌 처음 세 개의 시퀀스를 건너뛸 수 있기 때문입니다. 그러면 문제는 4차전이 언제 끝났는지 어떻게 알 수 있느냐가 됩니다. 삭제하고 싶은지 스스로에게 물어보세요많은 종류의네 번째 필드에 쉼표가 있는지 또는 항상 쉼표가 없거나 1개가 있는지 여부입니다.

이 답변을 위해 네 번째 필드에는 제거해야 할 최대 하나의 쉼표가 포함되어 있다고 가정합니다. 또한 쉼표는 하나 이상의 숫자 뒤와 최소한 하나의 숫자 앞에 나타난다고 가정하겠습니다. 그런 다음 Vim에서 사용할 수 있습니다.

:%s/\v(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/

또는 Sed를 사용하려는 경우:

sed -r 's/(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/' filename.csv

어떻게 작동하나요?

정규식은 (([^,]*,){3})처음 세 개의 필드와 그 뒤의 필드 구분 기호를 일치시키며, 모두 동일하게 유지하려고 합니다. [^,]를 제외한 모든 단일 문자와 일치합니다 ,. 그러면 *정확히 1개가 아닌 0개 이상의 일치 항목이 생성됩니다. 다음 내용은 ,쉼표가 아닌 필드 뒤의 실제 쉼표와 일치합니다. 이는 모두 그룹화 ( )되어 {3}적용되어 한 번이 아닌 세 번 일치하게 됩니다. 그 다음에저것모든 것이 그룹화되어 를 사용하여 액세스할 수 있습니다 \1. (내부 그룹도 캡처하고할 수 있다방문으로 이용 가능합니다 \2. )

그런 다음 ([0-9]+)하나 이상의 ( +) 숫자 ( )를 일치시키고 로 액세스할 수 있도록 [0-9]일치 항목 ( )을 캡처 합니다 .( )\3,아니요유지됩니다. 그런 다음 ([0-9])로 액세스할 수 있도록 숫자를 캡처합니다 \4.

단일 그룹을 사용하여 정규식을 좀 더 간단하게 만들 수 있습니다 \1. 나는 이것이 레코드의 구조를 숨긴다고 느끼기 때문에 피했습니다. 레코드는 쉼표로 구분된 필드로 구성되어 있지만 그렇게 해도 아무런 문제가 없습니다. 이렇게 하면 가 되므로 교체 모드에서는 대신 을 사용합니다 .\3(([^,]*,){3}[0-9]+)\4\3\1\3\1\3\4

마침내,이것\vVim 정규식의 시작 부분에서 확장된 정규식 구문을 사용할 수 있도록 서비스 -r에 전달됩니다 . sed그래서 and 대신에 and 대신에 and (를 쓸 수 있었습니다 .)\(\)+\+

답변2

다음 정규식을 사용하여 vim에서 이 작업을 수행할 수 있습니다.

ㅋㅋㅋ %s/\([^,]\+,\)\{3}[^,]*\zs,\ze[^,]*\(,[^,]\+\)\{2}//

설명은 다음과 같습니다.

  • \([^,]\+,\)\{3}3개의 csv 필드와 다음 쉼표가 정확히 일치합니다.

  • \(,[^,]\+\)\{2}2개의 csv 필드와 앞의 쉼표가 정확히 일치합니다.

  • 이 두 표현식 사이의 내용은 쉼표를 제거해야 하는 필드를 캡처합니다.

답변3

$ sed 's/,\([0-9]\+\),\([0-9]\+\)/,\1\2/' input
r1,col1,col2,35000,col4,col5
r2,col1,col2,1000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4325.33,col4,col5

사용된 표현을 설명하세요.

  NODE                     EXPLANATION
  ,                        ','
  (                        group and capture to \1:
    [0-9]+                   any character of: '0' to '9' (1 or more
                             times (matching the most amount
                             possible))
  )                        end of \1
  ,                        ','
  (                        group and capture to \2:
    [0-9]+                   any character of: '0' to '9' (1 or more
                             times (matching the most amount
                             possible))
  )                        end of \2

그런 다음 일치 항목을 ,\1\2.

답변4

awk이 작업 에 사용할 수 있습니다 . 이 스크립트는 네 번째 열의 여러 쉼표를 처리할 수 있습니다. 이 경우를 처리하기 위해 를 사용하는 것이 어렵다고 생각합니다(쉼표가 여러 개임) vim. 그러나 사용하기 쉽습니다 awk.

노트:이 솔루션은 6개의 열에만 작동합니다( r1열도 세고 있습니다).

awk '
BEGIN {
    FS = ",";
    OFS = ",";
}
{
    accum = "";
    for(i = 4; i < NF - 1; i++) {
        accum = accum $i;       
    }

    print $1, $2, $3, accum, $(NF - 1), $NF;
}' input.txt

입력(테스트를 위해 대상 필드에 여러 개의 쉼표가 있는 행 추가)

r1,col1,col2,35,000,col4,col5
r2,col1,col2,1,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4,325.33,col4,col5
r5,col1,col2,4,325,250.33,col4,col5
r6,col1,col2,4,100,325,250.33,col4,col5

산출

r1,col1,col2,35000,col4,col5
r2,col1,col2,1000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4325.33,col4,col5
r5,col1,col2,4325250.33,col4,col5
r6,col1,col2,4100325250.33,col4,col5

관련 정보