Vimで複数の行(2つのブロック)をマージする


323

Vimで行の2つのブロックをマージする、つまり、行n..mを取得してそれらをlinesに追加したいと思いますa..b。疑似コードの説明が必要な場合:[a[i] + b[i] for i in min(len(a), len(b))]

例:

abc
def
...

123
45
...

なるはず

abc123
def45

手動でコピー&ペーストすることなくこれを行う良い方法はありますか?


だから...交互の行に参加したいですか?つまり、joinで行xを結合しx+2ますか?
12

1
いいえ、2つの別々のブロックがあります。Pseudocode-ish:[a[i] + b[i] for i in min(len(a), len(b))]
ThiefMaster

2
同様の質問(および回答!)をここで
NWS

回答:


880

確かに、1つのコピー/貼り付け(ブロックモードの選択を使用)でこれをすべて実行できますが、それはあなたが望んでいることではないと思います。

Exコマンドだけでこれを実行したい場合

:5,8del | let l=split(@") | 1,4s/$/\=remove(l,0)/

変形する

work it 
make it 
do it 
makes us 
harder
better
faster
stronger
~

work it harder
make it better
do it faster
makes us stronger
~

更新:これだけ多くの賛成票がある答えは、より完全な説明に値します。

Vimでは、パイプ文字(|)を使用して複数のExコマンドをチェーンすることができるため、上記は次と同等です。

:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/

多くのExコマンドは、一連の行をプレフィックス引数として受け入れます-上記の場合、5,8before del1,4before、before s///はコマンドが操作する行を指定します。

del指定された行を削除します。レジスタ引数を取ることができますが、それが指定されていない場合は@"、通常モードでの削除と同様に、名前のないレジスタに行をダンプします。 let l=split(@")次に、デフォルトの区切り文字である空白を使用して、削除された行をリストに分割します。次のように、削除された行に空白がある入力を適切に処理するには、

more than 
hour 
our 
never 
ever
after
work is
over
~

「work is」が2つのリスト要素に分割されないようにするには、別の区切り文字を指定する必要がありますlet l=split(@","\n")

最後に、置換s/$/\=remove(l,0)/では、各行の終わり($)を式の値に置き換えますremove(l,0)remove(l,0)リストを変更し、l最初の要素を削除して返します。これにより、削除された行を読み取る順序で置き換えることができます。代わりに、を使用して、削除された行を逆の順序で置き換えることができremove(l,-1)ます。


1
うーん...私は一度だけエンターを押す必要があります。また、2つの半分の間にスペースは挿入されません。行に後続スペースがある場合(「work it」の例のように)、それはまだそこにあります。のs/\s*$/代わりにを使用して、末尾のスペースを取り除くことができますs/$/
2012年

1
説明ありがとう。:sil5,8del | let l=split(@") | sil1,4s/$/\=remove(l,0)/ | call histdel("/", -1) | nohls実行後に検索履歴をクリーンアップするため、さらに優れているようです。また、Enterキーを押すように要求する「x more / less lines」というメッセージは表示されません。
ThiefMaster

11
あなたはその答えをフルvimの参照をしたい場合::help range:help :d:help :let:help split():help :s:help :s\=:help remove()
ブノワ

16
私がモデレーターになったのは、このような回答を投稿したい人がいることを確認するためです。良いショー:)
Tim Post

1
最初の4文の後に空白がない場合は問題があります。
Reman 2013年

58

問題を解決するエレガントかつ簡潔なExコマンドを組み合わせることによって得ることができる:global:move:joinのコマンドを。行の最初のブロックがバッファの最初の行から始まり、カーソルが2番目のブロックの最初の行の直前の行にあるとすると、コマンドは次のようになります。

:1,g/^/''+m.|-j!

この手法の詳細な説明については、同様の質問に対する私の回答を参照しください。」。


E16: Invalid Range-とにかくそれは動作します。それを削除する1,と、エラーなしで動作します。
ThiefMaster、

そして、残念ながらあなたは複数の答えを受け入れることはできません-そうでなければあなたの答えも緑の印を持つでしょう!
ThiefMaster

3
非常に素晴らしい!私は知らなかった:move:join!、またどのような''範囲引数(と意味:help '')、何+-(レンジ改質剤としてのもの:help range)。ありがとう!
ホタルブクロ

@ThiefMaster:このコマンドは、結合する2つの行の範囲が互いに隣接している場合に使用されるように設計されているため、カーソルは最初、2番目のブロックの最初の行の直前にある最初のブロックの最後の行に配置されます。(リンクされている回答と質問を参照してください。)コマンドは、ブロック内の行数が異なる場合でも意図したとおりに機能しますが、その場合はエラーメッセージが表示されます。sil!コマンドの前に付けることでエラーメッセージを抑制できます。
ib。

2
@ib .:この回答にも詳細な説明を入れるのは良い考えだと思います。
ThiefMaster

44

行のブロックを結合するには、次の手順を実行する必要があります。

  1. 3行目に移動します。 jj
  2. ビジュアルブロックモードに入ります。 CTRL-v
  3. カーソルを行末に固定します(長さが異なる行の場合は重要です): $
  4. 最後に移動: CTRL-END
  5. ブロックをカットします。 x
  6. 最初の行の終わりに移動します。 kk$
  7. ここにブロックを貼り付けます: p

ムーブメントは最高のものではありません(私はエキスパートではありません)が、望みどおりに動作します。それの短いバージョンがあることを願っています。

ここに前提条件があるので、この手法はうまく機能します。

  • 開始ブロックのすべての行(質問の例ではabcdef)は同じ長さXORを持っています
  • 開始ブロックの最初の行が最も長く、間にある追加のスペースは気にしません)XOR
  • 開始ブロックの最初の行は最長ではなく、最後にスペースを追加します。

うわー、それは面白いです!私はそれがそのようにうまくいくとは思っていませんでした。
voithos

13
これは、abcdefが同じ長さであるため、期待どおりに機能します。ブロックを選択すると、削除されたテキストのインデントが保持されるため、テキストを置くときにカーソルが短い行にある場合、長い行の文字の間に行が挿入され、カーソルが長い場合は短い行にスペースが追加されます1。
イズカタ

確かに...ブロックのコピーと貼り付けを使用して適切に行う方法はありますか?これは結局のところ、これを行う最も簡単な方法です(特に、何らかの理由でここでより複雑な方法を検索できない場合)。
ThiefMaster 2012年

2
@Izkataが言うように、長い行の間にテキストが挿入されるという問題に遭遇します。これを回避するには、最初の行の末尾にスペースを追加して最長にし、テキストのブロックを貼り付けます。それが完了すると、複数のスペースを1つに圧縮するのは簡単です:%s/ \+/ /g
Khaja Minhajuddin

1
set ve=all役立つはずです。vimdoc.sourceforge.net/ htmldoc / options.html# ' virtualedit 'を参照してください
Ben

19

これが私がそれを行う方法です(最初の行にカーソルを置いて):

qama:5<CR>y$'a$p:5<CR>dd'ajq3@a

次の2つのことを知っておく必要があります。

  • 2番目のグループの最初の行が始まる行番号(私の場合は5)、および
  • 各グループの行数(この例では3)。

これが起こっていることです:

  • qa次までのすべてqをの「バッファ」に記録しますa
  • ma 現在の行にマークを作成します。
  • :5<CR> 次のグループに行きます。
  • y$ 残りの行をヤンクします。
  • 'a 以前に設定したマークに戻ります。
  • $p 行の終わりに貼り付けます。
  • :5<CR> 2番目のグループの最初の行に戻ります。
  • dd それを削除します。
  • 'a マークに戻ります。
  • jq 1行下がり、記録を停止します。
  • 3@a 行ごとにアクションを繰り返す(私の場合は3)

1
両方入力した[Enter]後に押す:5必要があります。そうしないと機能しません。
ショーンJ.ゴフ、2012年

1
私はgvimにいます。GVimでそのコマンドをコピーして貼り付ける方法はありますか?^ Vは、現在ノーマル(?)モードになっている場合でも、挿入モードで自動的に貼り付けられます(これは、当然のことですが、これが通常必要です)。私は試しました:norm qama:5<CR>y$'a$p:5<CR>dd'ajq3@aが、それだけが実行されるようqです。
ThiefMaster

1
ThiefMaster:試してみましょう。CTRL-Vを押してからEnterキーを押し:let @a="ma:5^My$'a$p:5^Mdd'aj" | normal 4@a^M文字を入力します。
2012年

8

他の場所で述べたように、ブロック選択は進むべき道です。ただし、次のバリアントを使用することもできます。

:!tail -n -6 % | paste -d '\0' % - | head -n 5

この方法は、UNIXコマンドラインに依存しています。pasteユーティリティは、ライン合体のこの種を処理するために作成されました。

PASTE(1)                  BSD General Commands Manual                 PASTE(1)

NAME
     paste -- merge corresponding or subsequent lines of files

SYNOPSIS
     paste [-s] [-d list] file ...

DESCRIPTION
     The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file's newline characters with a single tab character,
     and writes the resulting lines to standard output.  If end-of-file is reached on an input file while other input files still contain data, the file is treated as if
     it were an endless source of empty lines.

実行する方法はブロック選択の使用だけではありません。それも最も単純なものではありません。私の回答paste -dに示されいるように望ましい(-like)動作は短いVimコマンドを使用して実装できます。
ib。

3
その上、私はWindowsを使用しているので、ソリューションにはLinuxマシンへのSSH接続を開き、エディターからターミナルに貼り付けて戻すことが含まれます。
ThiefMaster、

3

サンプルデータはランピオンのものと同じです。

:1,4s/$/\=getline(line('.')+4)/ | 5,8d

3

複雑になりすぎないように思います。virtualeditをオンに設定するだけです
:set virtualedit=all
ブロック123以下を選択します。
最初の列の後に置きます。

abc    123
def    45
...    ...

と1スペースの間の複数のスペースを削除します。

:%s/\s\{2,}/ /g

質問は実際にはスペースを要求しないので、私は次のようにします gvV:'<,'>s/\s+//g(vimは自動的にを挿入'<,'>するので、手動で入力する必要はありません)。
ベン・

2

私は複雑な繰り返しを使用します:)

これを考えると:

aaa
bbb
ccc

AAA
BBB
CCC

カーソルを最初の行に置いて、次のキーを押します。

qa}jdd''pkJxjq

次に、必要なだけ何回@aでも押します(その後、を使用できます@@)。

あなたは次のようになるはずです:

aaaAAA
bbbBBB
cccCCC

(プラス改行。)

説明:

  • qa で複雑な繰り返しの記録を開始します a

  • } 次の空行にジャンプします

  • jdd 次の行を削除します

  • '' 最後のジャンプの前の位置に戻ります

  • p 削除した行を現在の行の下に貼り付けます

  • kJ 現在の行を前の行の最後に追加する

  • xJ結合された行の間にあるスペースを削除します。スペースが必要な場合は、これを省略できます

  • j 次の行に行く

  • q 複雑な繰り返し録音を終了する

その後、に@a格納された複合繰り返しを実行aするために使用@@し、最後に実行された複合繰り返しを再実行するために使用できます。


1

これを実現する方法はいくつもあります。次の2つの方法のいずれかを使用して、テキストの2つのブロックをマージします。

最初のブロックが1行目にあり、2番目のブロックが10行目から始まり、カーソルの初期位置が1行目にあるとします。

(\ nはEnterキーを押すことを意味します。)

1. abc
   def
   ghi        

10. 123
    456
    789

コマンドを使用してマクロで:コピー、貼り付け、結合。

qaqqa:+ 9y \ npkJjq2 @ a10G3dd

コマンドを使用するマクロで、n番目の行番号で行を移動して結合します。

qcqqc:10m。\ nkJjq2 @ c

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.