Zam
Zam

Reputation: 377

How to replace once, of each output of one pattern?

I want to replace a pattern, i don't know the exact word. I need to replace the first occurance of these words.

Input:-

For example, this is just{an} example to show my{need}. This para{has} no meaning, just{an} example. Imagine that my{replace} should done in this para. For example, this is just{an} example to show my{need}. This para{has} no meaning, just{an} example. Imagine that my{replace} should done in this para. Some more{text}

Required output:-

For example, this is Replace_Word example to show Replace_Word. This Replace_Word no meaning, just{an} example. Imagine that Replace_Word should done in this para. For example, this is just{an} example to show my{need}. This para{has} no meaning, just{an} example. Imagine that my{replace} should done in this para. Some Replace_Word

Example pattern s/\(\w*{\w*}\)/Replace_word/g

I am a beginner in vim. I know this is wrong. I think, need to use for loop, etc

0,/Word_to_find/s/Word_to_find/Replace_word/g

Upvotes: 1

Views: 54

Answers (2)

Kent
Kent

Reputation: 195059

Source this function, then in your input file buffer do:

call ReplaceFirst('\S\+{[^}]*}',"REPLACE_WORD")

it should does what you want:

function! ReplaceFirst(pat, rep) 
    let end = line('$')
    let pat_dict = {}
    for i in range(1,end)
        let line = getline(i)
        while 1
            let found = matchstr(line, a:pat)
            if found == ""
                break
            endif
            let pat_dict[found] = 0
            let line = substitute(line, a:pat, '','1')
        endwhile
    endfor
    "do replacement 
    for  k in keys(pat_dict)
        execute 'normal! gg'
        execute '/\V'.k
        execute 's/\V'.k.'/'.a:rep.'/'
    endfor
endfunction

test here:

enter image description here

Note that this function is not so generic, if your pattern contains /, the function may fail. At least it shows my idea. For those enhancements, you can make it complete.

Upvotes: 1

yolenoyer
yolenoyer

Reputation: 9445

The following do the trick, but it really could be improved:

function! ReplaceFirst(line1, line2, pattern, replace)
    let words = []  " To store all possible patterns
    for i in range(a:line1, a:line2)  " Loop over lines in the desired range
        let line = getline(i)
        let c = 1  " Counter for multiple matches in the same line
        while 1  " For each match in the same line:
            let s = matchstr(line, a:pattern, 0, c)
            if s == ""
                break
            endif
            if index(words, s) == -1  " If this match was not already stored:
                call add(words, s)  " Add this match
            endif
            let c = c + 1  " Go to next match in the same line
        endw
    endfor

    for word in words  " For all found matches:
        call cursor(a:line1, 1)  " Go to the beginning of range,
        call search('\V'.word, 'c')  " Then to the first occurence of the match
        " Replace the first occurence in the line:
        exe 's/\V'.word."/".a:replace
    endfor
endf

" Command that takes two args: first one is the pattern, second one is the 
" replace word:
command! -range -nargs=* ReplaceFirst call ReplaceFirst(<line1>, <line2>, <f-args>)

" Example:
" :%ReplaceFirst \<\w*{\w*} REPLACE_WORD

Upvotes: 1

Related Questions