파일의 문자열 일부를 바꾸려고 합니다.
예를 들어 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,000
1( )로 시작됩니다.
처음 세 개의 필드 자체에 쉼표가 포함되어 있지 않다는 것을 알면 문제가 훨씬 쉬워집니다. 쉼표를 제거하기 전에 쉼표가 뒤따르는 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
마침내,이것\v
Vim 정규식의 시작 부분에서 확장된 정규식 구문을 사용할 수 있도록 서비스 -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