각 경기를 증분 카운터로 바꾸는 방법은 무엇입니까?


14

특정 패턴의 각 항목을 검색하고 1각 일치마다 하나씩 증가 하는 10 진수로 바꾸고 싶습니다 .

카운터를 늘리는 것이 아니라 각 금액을 고정 금액으로 수정하는 것과 비슷한 단어로 된 질문을 찾을 수 있습니다. 다른 유사한 질문은 증분 카운터 대신 행 번호를 삽입하는 것에 관한 것입니다.

예를 들면 다음과 같습니다.

#1
#1.25
#1.5
#2

후:

#1
#2
#3
#4

내 실제 데이터에는 다시 번호를 매길 물건 주위에 더 많은 텍스트가 있습니다.


2
당신이 있다면 perldo사용할 수 있습니다:%perldo s/#\K\d+(\.\d+)?/++$i/ge
Sundeep

@Sundeep : 바닐라 Windows 10을 사용한다고 언급했습니다. 미안합니다!
hippietrail

답변:


15

상태로 대체해야합니다. SO에 대한 이러한 종류의 문제에 대한 (/ 여러?) 완전한 솔루션 을 제공 한 것을 기억 합니다.

다음은 또 다른 방법입니다 (1). 이제 2 단계로 진행하겠습니다.

  • 내가 사용할 더럽고 복잡한 트릭에 필요한 더미 목록 변수
  • 이 더미 배열의 len을 삽입하는 치환은 각 일치하는 항목을 채 웁니다.

다음을 제공합니다.

:let t=[]
:%s/#\zs\d\+\(\.\d\+\)\=\ze/\=len(add(t,1))/g

정규 표현식을 vim하는 데 익숙하지 않은 경우 일치하는 하위 패턴을 사용 :h /\zs하고 \ze지정하기 위해 가능한 한 일련의 숫자와 점 및 기타 숫자가 일치합니다. 이것은 부동 소수점 숫자에 완벽하지는 않지만 여기서는 충분합니다.

참고 : 간단한 인터페이스를 위해서는 몇 가지 기능 + 명령으로 마무리해야합니다. 다시, SO / vim ( here , here , here ) 에 대한 예가 있습니다. 요즘에는이 트릭을 명령에 래핑하는 것에 신경 쓰지 않을 정도로 vim이 충분하다는 것을 알고 있습니다. 실제로 첫 번째 시도 에서이 명령을 작성할 수 있지만 명령의 이름을 기억하는 데 몇 분이 걸립니다.


(1) 목표는 대체 사이의 상태를 유지하고 현재 발생을 현재 상태에 의존하는 것으로 대체하는 것입니다.

덕분에 :s\=계산 결과를 삽입 할 수 있습니다.

국가의 문제를 유지합니다. 외부 상태를 관리하는 함수를 정의하거나 외부 상태를 업데이트합니다. C (및 관련 언어)에서는 length++or 와 같은 것을 사용할 수 있습니다 length+=1. 불행히도, vim 스크립트에서는 +=즉시 사용할 수 없습니다. 그것은 함께 사용될 수 필요 :set하거나 함께 :let. 즉 :let length+=1, 숫자 가 증가하지만 아무것도 반환하지 않습니다. 우리는 쓸 수 없습니다 :s/pattern/\=(length+=1). 우리는 다른 것이 필요합니다.

뮤팅 기능이 필요합니다. 즉, 입력을 변경하는 기능. 우리는이 setreg(), map(), add()아마 더합니다. 그들부터 시작합시다.

  • setreg()레지스터를 변경합니다. 완전한. setreg('a',@a+1)@Doktor OSwaldo의 솔루션에서와 같이 작성할 수 있습니다 . 그러나 이것은 충분하지 않습니다. setreg()(Pascal, Ada ...를 아는 사람들 중) 이것은 아무것도 반환하지 않음을 의미합니다. 실제로는 무언가를 반환합니다. 명목 이탈 (예 : 비 예외 이탈)은 항상 무언가를 반환합니다. 기본적으로 무언가를 반환하는 것을 잊었을 때 0이 반환 되며 내장 함수에도 적용됩니다. 그래서 그의 솔루션에서 대체 표현은 실제로 \=@a+setreg(...)입니다. 까다 롭지 않습니까?

  • map()또한 사용될 수있었습니다. 단일 0 ( :let single_length=[0]) 으로 목록에서 시작 하면로 인해 증가 할 수 있습니다 map(single_length, 'v:val + 1'). 그런 다음 새 길이를 반환해야합니다. 달리 setreg(), map()그 돌연변이 입력을 반환합니다. 완벽합니다. 길이는 목록의 첫 번째 (고유 한 마지막 위치) 위치에 저장됩니다. 대체 표현식은입니다 \=map(...)[0].

  • add()내가 습관적으로 자주 사용하는 것입니다 map(). 아이디어 add()는 목록을 현재 상태로 사용하고 각 대체 전에 끝에 무언가를 추가하는 것입니다. 나는 종종 새로운 값을 목록의 끝에 저장하고 대체를 위해 사용합니다. 으로 add()또한 돌연변이 입력 목록을 반환, 우리가 사용할 수 있습니다 \=add(state, Func(state[-1], submatch(0)))[-1]. OP의 경우 지금까지 몇 개의 일치 항목이 감지되었는지 기억하면됩니다. 이 상태 목록의 길이를 반환하면 충분합니다. 따라서 내 \=len(add(state, whatever)).


나는 이것을 이해한다고 생각하지만 왜 배열을 사용하는 트릭과 길이를 변수에 추가하는 것과 비교할 수 있습니까?
hippietrail

1
이것은 \=표현식을 기대하기 때문이며 C와 달리 표현식을 i+=1증가 시키고 리턴하는 것이 아닙니다 . 이것은 뒤에 \=카운터를 수정할 수 있고 표현식을 반환하는 무언가가 필요하다는 것을 의미합니다 (해당 카운터와 동일). 지금까지 내가 찾은 것은 목록 (및 사전) 조작 기능입니다. @Doktor OSwaldo는 다른 돌연변이 기능 ( setreg())을 사용했습니다. 차이점은 setreg()아무것도 반환하지 않는다는 것입니다. 즉 항상 숫자를 반환합니다 0.
Luc Hermitte

와우, 재밌어요! 귀하의 트릭과 그의 마술은 너무 마술 적이므로 귀하의 답변이 귀하의 답변에 설명되어 도움이 될 것이라고 생각합니다. 나는 가장 유창한 Vimscripters만이 직관적이지 않은 관용구를 알고 있다고 가정합니다.
hippietrail

2
@hippietrail. 추가 정밀도가 필요한지 알려주세요.
Luc Hermitte

13
 :let @a=1 | %s/search/\='replace'.(@a+setreg('a',@a+1))/g

그러나 레지스터를 덮어 씁니다 a. 나는 그것이 luc의 대답보다 조금 더 직설적이라고 생각하지만 어쩌면 그의 것이 더 빠를 수도 있습니다. 이 솔루션이 그의 솔루션보다 나쁘다면 그의 답변이 더 나은 이유에 대한 의견을 듣고 싶습니다. 답변을 개선하기위한 모든 의견은 대단히 감사하겠습니다!

(또한 /programming/43539251/how-to-replace-finding-words-with-the-different-in-each-occurrence-in-vi-vim 의 SO 답변을 기반으로합니다. -edi / 43539546 # 43539546 )


@a+setreg('a',@a+1)보다 짧은 방법 이 없습니다 len(add(t,1)). 그렇지 않으면 이것은 좋은 다른 더러운 속임수입니다 :). 나는 이것을하지 않았습니다. 대체 텍스트에서 사전 돌연변이 함수의 사용과 관련하여 :s및의 substitute()명시 적 루프보다 훨씬 빠릅니다. 따라서 lh-vim-lib에서 목록 함수를 구현 합니다. 귀하의 솔루션이 내 것과 동등 할 것 같고 조금 더 빠를 수도 있습니다.
Luc Hermitte

2
환경 설정과 관련하여 한 가지 이유로 내 솔루션을 선호합니다 @a. 수정되지 않은 채로 둡니다 . 스크립트에서 이것은 중요한 IMO입니다. 대화식 모드에서는 최종 사용자로서 어떤 레지스터를 사용할 수 있는지 알고 있습니다. 레지스터를 사용하는 것은 덜 중요합니다. 내 솔루션에서 대화 형 모드에서 전역 변수가 엉망입니다. 스크립트에서 지역 변수가 될 것입니다.
Luc Hermitte

@LucHermitte 죄송합니다. 내 솔루션은 실제로 귀하의 것보다 짧지 않습니다. 그런 말을 작성하기 전에 더 잘 읽어야합니다. 답변에서 해당 내용을 삭제했으며 사과하고 싶습니다. 흥미로운 의견에 감사드립니다. 감사합니다.
Doktor OSwaldo

걱정하지 마십시오. 정규식으로 인해 입력해야 할 것이 많다고 생각하기 쉽습니다. 또한 자발적으로 솔루션이 복잡하다는 것을 인정합니다. 피드백을 환영합니다. :)
Luc Hermitte

1
실제로 당신은 rigth입니다. 대부분의 경우 배열의 마지막 위치에 저장하는 다른 정보를 추출합니다.이 정보는 마지막에 삽입하는 마지막 요소입니다. 예를 들어에 대해 +3다음과 같이 쓸 수 \=add(thelist, 3 + get(thelist, -1, 0))[-1]있습니다.
Luc Hermitte

5

나는 2 년 전에 물었던 유사하지만 다른 질문을 발견하고 내가하고있는 일을 완전히 이해하지 않고 그 답 중 하나를 바꿀 수 있었고 훌륭하게 작동했습니다.

:let i = 1 | g/#\d\+\(\.\d\+\)\=/s//\=printf("#%d", i)/ | let i = i+1

특히 나는 왜 내 것이 사용되지 않는지 %또는 왜 다른 대답이 어떤 이유로 피하는 일반 변수를 사용하는지 이해하지 못합니다 .


1
그것은 또한 가능성입니다. 여기서 가장 큰 단점은 경기 당 하나의 대체 명령을 사용한다는 것입니다. 아마 느려질 것입니다. 우리가 일반 변수를 사용하지 않는 이유는 일반 변수로 업데이트되지 않기 때문입니다 s//g. 어쨌든 그것은 흥미로운 해결책입니다. 어쩌면 @LucHermitte가 vimscript에 대한 나의 지식이 그의 것에 비해 상당히 제한되어 있기 때문에 장단점에 대해 더 많이 말할 수 있습니다.
Doktor OSwaldo

1
@DoktorOSwaldo. 없이 -이 솔루션은 긴 시간 동안 일하고있다 생각 printf()리스트는 빔 7에 도입하지만 내가 (? / 기억하지 않았다) 예상하지 않았을 인정해야으로 - 비록 <bar>의 범위에 속하는 :global-IOW, 내가 기대했던 시나리오 :sub는 일치하는 줄에 적용 한 다음 i맨 끝에 한 번 증가하는 것이 었습니다 . 이 솔루션이 약간 느릴 것으로 예상합니다. 하지만 정말 중요합니까? 중요한 것은 메모리 + 시행 착오에서 작동하는 솔루션을 얼마나 쉽게 얻을 수 있는지입니다. 예를 들어 Vimgolfers는 매크로를 선호합니다.
Luc Hermitte

1
@LucHermitte 네, 같은 것을 ecpexted하고 속도는 중요하지 않습니다. 나는 그것이 좋은 대답이라고 생각하고 다시 그것으로부터 무언가를 배웠다. g/s//스코프 동작으로 인해 다른 트릭이 발생할 수 있습니다. 그래서 흥미로운 답변과 토론에 감사드립니다. 나는 종종 =) 답변을 제공하여 많은 것을 배우지 않습니다.
Doktor OSwaldo

4

이 페이지 에는 이미 세 가지 훌륭한 답변 이 있지만 Luc Hermitte가 의견에서 제안한 것처럼 커프를 수행하는 경우 중요한 것은 작업 솔루션을 쉽고 빠르게 시작할 수 있다는 것입니다.

따라서 이것은 실제로 전혀 사용하지 않는 문제입니다 :substitute. 일반적인 일반 모드 명령과 재귀 매크로를 사용하여 쉽게 해결할 수있는 문제입니다.

  1. (필요한 경우) 먼저을 끕니다 'wrapscan'. 우리가 사용할 정규 표현식은 원하는 결과 텍스트와 초기 텍스트를 일치 시키므로 'wrapscan'매크로를 계속 사용하면 매크로가 계속 재생됩니다. (또는 무슨 일이 일어나고 있는지 알 때까지을 누르십시오 <C-C>.) :

    :set nowrapscan
    
  2. 기존 답변에서 이미 언급 한 것과 동일한 기본 정규식을 사용하여 검색어를 설정하십시오.

    /#\d\+\(\.\d\+\)\?<CR>
    
  3. (필요한 경우) 필요한N 만큼 여러 번 눌러 첫 번째 경기로 돌아갑니다 .

  4. (필요한 경우) 첫 번째 일치 항목을 원하는 텍스트로 변경하십시오.

    cE#1<Esc> 
    
  5. "q레지스터를 지우고 매크로 기록을 시작하십시오.

    qqqqq
    
  6. 현재 카운터 Yank :

    yiW
    
  7. 다음 경기로 이동 :

    n
    
  8. 현재 카운터를 방금 막은 카운터로 교체하십시오.

    vEp
    
  9. 카운터를 늘리십시오.

    <C-A>
    
  10. 매크로를 재생 q합니다. "q5 단계에서 지운 레지스터 가 여전히 비어 있으므로이 시점에서 아무 일도 일어나지 않습니다.

    @q
    
  11. 매크로 기록을 중지하십시오.

    q
    
  12. 새로운 매크로를 재생 해보세요!

    @q
    

모든 매크로와 마찬가지로 위에서 설명한대로 설명하면 많은 단계처럼 보이지만 실제로 입력하는 것은 매우 빠릅니다. 재귀 매크로 기록 보일러 플레이트와 별개로 모두 규칙적입니다. 편집 명령 편집하는 동안 항상 수행하고 있습니다. 내가 생각에 접근 하는 것조차도해야 할 유일한 단계 는 2 단계였습니다. 여기서 검색을 수행하기 위해 정규 표현식을 작성했습니다.

이 명령 줄 모드 명령과 키 입력의 일련의 포맷, 이러한 유형의 솔루션의 속도는 더욱 분명해진다 : 나는 그것을 입력 할 수있는 나는 최대한 빨리 거의 다음을 연상 수 1 :

:set nowrapscan
/#\d\+\(\.\d\+\)\?
cE#1<Esc>qqqqqyiWnvEp<C-A>@qq@q

아마도이 페이지의 다른 솔루션을 약간 생각하고 문서 2를 참조하여 생각해 낼 수 있었을 것입니다. 하지만 매크로가 어떻게 작동하는지 이해하면 일반적으로 편집하는 속도에 관계없이 실제로 쉽게 벗어날 수 있습니다.

1 :이 있습니다 매크로 더 많은 생각을 요구하는 경우가 있지만, 나는 그들이 실제로 많이 올라 오지 않는 찾을 수 있습니다. 그리고 일반적으로 발생하는 상황은 매크로가 유일한 실용적인 해결책입니다.

2 : 다른 응답자가 비슷한 방식으로 솔루션을 쉽게 만들 수 없다는 것을 암시하지 않습니다. 그들은 개인적으로 쉽게 할 수없는 기술 / 지식 만 있으면됩니다. 그러나 모든 Vim 사용자는 정기적 인 편집 명령 사용법을 알고 있습니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.