各マッチをインクリメントカウンターに置き換える方法は?


14

特定のパターンが出現するたびに検索を開始し1、一致ごとに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を使用しています。
ヒッピートレイル2017

回答:


15

状態による代替が必要です。SOでのこの種の問題に対して(/いくつか?)完全なソリューションを提供したことを覚えています。

次に進む別の方法を示します(1)。次に、2つのステップに進みます。

  • 私が使用するダーティで複雑なトリックに必要なダミーリスト変数
  • このダミー配列のlenを挿入する置換で、一致する各出現箇所に入力します。

それは与える:

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

vim正規表現に慣れていない場合は、とを使用:h /\zs\zeて、照合するサブパターンを指定します。その後、一連の数字とそれに続くドットやその他の数字を照合します。これはどの浮動小数点数にも完全ではありませんが、ここではこれで十分です。

注:シンプルなインターフェースの場合は、それを2つの関数+コマンドでラップする必要があります。ここでも、SO / vim(hereherehere)の例があります。最近では、このトリックをコマンドにラップすることを気にしないほど十分なvimを知っています。確かに、最初の試行でこのコマンドを書くことができますが、コマンドの名前を覚えるのに数分かかります。


(1)目的は、置換の間の状態を維持し、現在の発生を現在の状態に依存するものに置き換えることです。

おかげで:s\=、計算から生じた何かを挿入することができます。

状態の問題のままです。外部状態を管理する関数を定義するか、外部状態を更新します。C(および関連言語)では、length++またはのようなものを使用できたはずlength+=1です。残念ながら、vimスクリプトで+=は、そのままでは使用できません。:setまたはとともに使用する必要があります:let。つまり:let length+=1、数値をインクリメントしますが、何も返しません。書けません:s/pattern/\=(length+=1)。他に何かが必要です。

変異機能が必要です。つまり、入力を変更する関数です。我々は持っているsetreg()map()add()おそらくより。それらから始めましょう。

  • setreg()レジスタを変更します。完璧です。setreg('a',@a+1)@Doktor OSwaldoのソリューションのように書くことができます。それでも、これでは不十分です。setreg()(パスカル、エイダを知っている私たちの間で...)関数よりも手続きの詳細です。つまり、何も返されません。実際には、それは何かを返します。名目上の出口(つまり、例外でない出口)は常に何かを返します。デフォルトでは、何かを返すのを忘れた場合、0が返されます。これは、組み込み関数にも適用されます。そのため、彼のソリューションでは置換式は実際に\=@a+setreg(...)です。トリッキーですね。

  • map()使用することもできます。0(:let single_length=[0])が1つのリストから開始する場合、のおかげでそれを増やすことができますmap(single_length, 'v:val + 1')。次に、新しい長さを返す必要があります。とは異なりsetreg()map()変化した入力を返します。それは完璧です、長さはリストの最初の(そして一意の、したがって最後の)位置に保存されます。置換式はである可能性があります\=map(...)[0]

  • add()私がよく使う習慣の1つです(map()実際、私は実際に行ったことがありますが、それぞれのパフォーマンスのベンチマークはまだ行っていません)。のアイデアadd()は、現在の状態としてリストを使用し、各置換の前に最後に何かを追加することです。私はよく新しい値をリストの最後に保存し、置換に使用します。変更されadd()た入力リストも返すので、次のものを使用できます\=add(state, Func(state[-1], submatch(0)))[-1]。OPの場合、これまでに検出された一致の数を覚えておけば十分です。この状態リストの長さを返すだけで十分です。したがって、私の\=len(add(state, whatever))


私はこれを理解していると思いますが、なぜ配列にトリックを追加して変数に追加するのと比較して長さが長いのですか?
ヒッピートレイル2017

1
これは\=、式を期待し、Cとi+=1は異なり、インクリメントて式を返すものではないためです。これは、背後で\=カウンターを変更でき、式(そのカウンターと同じ)を返すものが必要であることを意味します。これまでのところ、私が見つけた唯一のものは、リスト(および辞書)操作関数です。@Doktor OSwaldoは別の変更関数(setreg())を使用しています。違いは、setreg()何も返さないこと0です。つまり、常に数値を返します。
Luc Hermitte、2017

うわー、面白い!あなたのトリックと彼の両方は非常に不思議なので、あなたの答えはあなたの答えでそれらを説明することから利益を得ると思います。最も流暢なvimscripterだけがそのような直感的でないイディオムを知っていると思います。
ヒッピートレイル2017

2
@hippietrail。説明を追加しました。より具体的な精度が必要かどうかをお知らせください。
Luc Hermitte、2017

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 -edi / 43539546#43539546


がどのよう@a+setreg('a',@a+1)に短いかわかりませんlen(add(t,1))。それ以外の場合、これは他の素敵なトリックです:)。私はこれを考えていません。置換テキスト、辞書変異機能の使用に関する:sそしてsubstitute()、私はこのことを指摘しているが、はるかに高速であることの明示的なループ-それゆえLH-VIM-libに私のリスト機能の実装。あなたの解決策は私のものと同じだと思いますが、少し速くなるかもしれません、私にはわかりません。
Luc Hermitte、2017

2
設定に関して、私は単一の理由で私のソリューションを好み@aます。スクリプトでは、これは重要なIMOです。対話モードでは、エンドユーザーとして、どのレジスタを使用できるかがわかります。レジスタをいじることはそれほど重要ではありません。私のソリューションでは、インタラクティブモードで、グローバル変数が乱されています。スクリプトでは、ローカル変数になります。
Luc Hermitte、2017

@LucHermitte申し訳ありませんが、私の解決策は確かにあなたの解決策よりも短くはありません。そのようなステートメントを書く前に、もっとよく読んでおくべきです。上記の発言を私の回答から削除しました。お詫び申し上げます。興味深いフィードバックをありがとうございます。
Doktor OSwaldo 2017

心配しないでください。正規表現のため、入力することがたくさんあると考えるのは簡単です。また、自分の解決策が複雑であることを自発的に認めます。フィードバックをお待ちしています。:)
Luc Hermitte 2017

1
確かにあなたは厳格です。ほとんどの場合、配列の最後の位置に格納する別の情報を抽出します。これは、最後に挿入するもの(最後の要素)です。たとえば、の場合、の+3ように書くことができます\=add(thelist, 3 + get(thelist, -1, 0))[-1]
Luc Hermitte、2017

5

私は数年前に尋ねた同様の異なる質問を見つけ、私が何をしているかを完全に理解せずに答えの1つを変更することができ、それはうまく機能しています:

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

具体的には、なぜ私が使用しないの%か、なぜ他の回答が何らかの理由で回避するプレーン変数を使用するのか理解できません。


1
それも可能性です。ここでの主な欠点は、マッチごとに1つの代替コマンドを使用することです。そのため、おそらく遅くなります。プレーン変数を使用しない理由は、通常のs//gステートメントでは更新されないためです。とにかくそれは興味深い解決策です。多分@LucHermitteは長所と短所についてあなたにもっと教えてくれるかもしれません、なぜならvimscriptに関する私の知識は彼と比較してかなり制限されているからです。
Doktor OSwaldo 2017

1
@DoktorOSwaldo。なし-私は、このソリューションは、長い時間のために働いてきたと思いprintf()リストはVimの7で導入されたとして、しかし、私は私が予想しなかったであろう認めなければならない(/覚えていない?) -しかし<bar>の範囲に属するもの:global-IOW、私が期待していたシナリオは:sub、一致する行にを適用し、i最後に1回インクリメントすることでした。このソリューションは少し遅いと思います。しかし、それは本当に重要ですか?重要なことは、メモリ+試行錯誤から実用的なソリューションを簡単に見つけ出すことができることです。たとえば、Vimgolferはマクロを好みます。
Luc Hermitte、2017

1
@LucHermitteええ、私は同じことをecpextしました、そして速度は関係ありません。いい答えだと思いますし、そこからまた学びました。たぶん、g/s//スコープの振る舞いは他の汚いトリックを可能にします。興味深い回答とディスカッションの両方に感謝します。私は回答を与えることからそれほど多くを学ぶことはありません=)。
Doktor OSwaldo 2017

4

このページにはすでに3つの 優れた 回答がありますが、Luc Hermitteがコメント示唆しているように、これをすぐに実行している場合、重要なことは、実用的なソリューションにすばやく簡単にアクセスできることです。

そのため、これは実際にはまったく使用:substituteしない問題です。通常のノーマルモードコマンドと再帰マクロを使用して簡単に解決できる問題です。

  1. (必要に応じて)まず、をオフにし'wrapscan'ます。これから使用する正規表現は、目的の結果テキストと初期テキストを照合するため、'wrapscan'onを指定すると、マクロはそれ以外の場合は永久に再生し続けます。(または、何が起こっているのかを理解してを押すまで<C-C>)。

    :set nowrapscan
    
  2. 検索用語を設定します(既存の回答ですでに言及されているのと同じ基本正規表現を使用):

    /#\d\+\(\.\d\+\)\?<CR>
    
  3. (必要な場合)必要なだけ押して、最初の試合に戻りNます。

  4. (必要に応じて)最初の一致を目的のテキストに変更します。

    cE#1<Esc> 
    
  5. "qレジスタをクリアして、マクロの記録を開始します。

    qqqqq
    
  6. 現在のカウンターをヤンクします。

    yiW
    
  7. 次の試合にジャンプ:

    n
    
  8. 現在のカウンターを、先ほどヤンクしたカウンターに置き換えます。

    vEp
    
  9. カウンターをインクリメントします。

    <C-A>
    
  10. マクロを再生しqます。"q手順5でクリアしたため、レジスタはまだ空です。この時点では何も起こりません。

    @q
    
  11. マクロの記録を停止します。

    q
    
  12. 新しいマクロを再生して、見てください!

    @q
    

すべてのマクロと同様に、上記で説明したように説明すると、これは多くの手順のように見えますが、実際にこれらを入力するのは非常に速いことに注意してください。再帰的なマクロ記録のボイラープレートは別として、これらはすべて通常のものです編集コマンド編集中は常に実行しています。思考に近づくことさえ何でもしなければならなかった唯一のステップは、検索を実行するために正規表現を書いたステップ2でした。

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.