13

次のファイルがあるとします

<block>
    <foo val="bar"/>
    <foo val="bar"/>
</block>
<block>
    <foo val="bar"/>
    <foo val="bar"/>
</block>

どうすればそれを作ることができますか

<block>
    <foo val="bar1"/>
    <foo val="bar"/>
</block>
<block>
    <foo val="bar1"/>
    <foo val="bar"/>
</block>

私がやろうとしたことの 1 つは、マクロを記録し、と をそれぞれ 1 回:%s/bar/bar1/gc押しynから、そのマクロを編集しようとしたことです。なぜかマクロ編集ができません。:(

4

7 に答える 7

41

これが置換で実行できることを示すためだけに:

:let a = ['', '1']
:%s/bar\zs/\=reverse(a)[0]/g

概要

置換のたびに配列がその場で反転された後、bar変数の配列の最初の要素でevery の最後を置き換えます。a

詳細の栄光

  1. let a = ['', '1']a配列を保持する変数を定義します
  2. %s/.../.../ファイルのすべての行で置換を行います
  3. %s/bar\zs/.../バーで置換を行いますが、使用してバーの後に置換を開始します\zs
  4. \=コマンドの置換部分の内部で:sは、次の式の値を使用します
  5. reverse(a)reverse は単に配列を逆にしますが、インプレースで行います
  6. reverse(a)[0]reverse は反転した配列を返すので、最初の要素を取得します
  7. /g行内のすべてのオカレンスを置き換えます (オプション)

一般的なケース

:let a = ['a', 'b', 'c']
:%s/bar\zs/\=add(a, remove(a, 0))[-1]/g

一般的なケースでは、配列 をその場で「回転」aさせ、配列の最後の位置を置換の置換の値として使用します。

詳細については、次を参照してください。

:h :s
:h range
:h /\zs
:h :s\=
:h reverse(
:h :s_flags
:h Lists
:h add(
:h remove
于 2012-12-07T14:45:38.240 に答える
4

私はマクロでそれをします:

qv            start recording in register v
/"bar"/e<cr>  search for "bar" and position the cursor at the end of the match
i1<esc>       insert 1 before the cursor and go back to normal mode
n             jump to next match
q             stop recording

その後、実行します{count}@v

于 2012-12-07T14:02:24.773 に答える
4

使用できます

:%s/bar/bar1/gc

また、すべての試合で、交換するかどうかを尋ねられます。

それ以外の場合は、コンテンツ全体を指定して、最初のバーを bar1 に置き換えるだけです。

于 2012-12-07T13:26:04.610 に答える
1
:let dosubs=1
:%s/bar/\=[dosubs?'bar1':submatch(0),extend(g:,{'dosubs':!dosubs})][0]/g
于 2012-12-07T19:21:38.663 に答える
1

これは、そのトリックを実行するカスタム コマンドです。これは、replace 式を使用して行われた置換をカウントし、渡された追加の引数を使用して、置換を行う必要があるかどうかを決定します。(これにより、毎秒よりも複雑な配置が可能になります。) 次に、例は単純になります。

:%SubstituteSelected/\<bar\>/&1/ yn

(残念ながらかなり長い) 実装は次のとおりです。

":[range]SubstituteSelected/{pattern}/{string}/[flags] {answers}
"           Replace matches of {pattern} in the current line /
"           [range] with {string}, determining whether a particular
"           match should be replaced on the sequence of "y" or "n"
"           in {answers}. I.e. with "ynn", the first match is
"           replaced, the second and third are not, the fourth is
"           again replaced, ...
"           Handles & and \0, \1 .. \9 in {string}.
function! CountedReplace()
    let l:index = s:SubstituteSelected.count % len(s:SubstituteSelected.answers)
    let s:SubstituteSelected.count += 1

    if s:SubstituteSelected.answers[l:index] ==# 'y'
        if s:SubstituteSelected.replacement =~# '^\\='
            " Handle sub-replace-special.
            return eval(s:SubstituteSelected.replacement[2:])
        else
            " Handle & and \0, \1 .. \9 (but not \u, \U, \n, etc.)
            let l:replacement = s:SubstituteSelected.replacement
            for l:submatch in range(0, 9)
                let l:replacement = substitute(l:replacement,
                \   '\%(\%(^\|[^\\]\)\%(\\\\\)*\\\)\@<!' .
                \       (l:submatch == 0 ?
                \           '\%(&\|\\'.l:submatch.'\)' :
                \           '\\' . l:submatch
                \       ),
                \   submatch(l:submatch), 'g'
                \)
            endfor
            return l:replacement
        endif
    elseif s:SubstituteSelected.answers[l:index] ==# 'n'
        return submatch(0)
    else
        throw 'ASSERT: Invalid answer: ' . string(s:SubstituteSelected.answers[l:index])
    endif
endfunction
function! s:SubstituteSelected( range, arguments )
    let l:matches = matchlist(a:arguments, '^\(\i\@!\S\)\(.*\)\%(\%(^\|[^\\]\)\%(\\\\\)*\\\)\@<!\1\(.*\)\%(\%(^\|[^\\]\)\%(\\\\\)*\\\)\@<!\1\(\S*\)\s\+\([yn]\+\)$')
    if empty(l:matches)
        echoerr 'Invalid arguments'
        return
    endif
    let s:SubstituteSelected = {'count': 0}
    let [l:separator, l:pattern, s:SubstituteSelected.replacement, l:flags, s:SubstituteSelected.answers] = l:matches[1:5]

    execute printf('%ssubstitute %s%s%s\=CountedReplace()%s%s',
    \   a:range, l:separator, l:pattern, l:separator, l:separator, l:flags
    \)
endfunction
command! -bar -range -nargs=1 SubstituteSelected call <SID>SubstituteSelected('<line1>,<line2>', <q-args>)

編集

これを (関連するコマンドと共に) PatternsOnText pluginとして公開しました。

于 2012-12-07T15:38:13.407 に答える
1

これを試して:

:%s/bar\(.*\)\n\(.*\)bar/bar1\1\r\2bar
于 2012-12-07T13:31:27.993 に答える