行の順序を逆にする方法は?


24

最初の行が最後に表示され、最後の行が最初に表示されるように行の順序を逆にするにはどうすればよいですか?(バッファー内のすべての行、アドレス範囲、または行単位の視覚モード選択である可能性があります。)

変身したい

rat
ox
tiger
⋮
dog
pig

pig
dog
⋮
tiger
ox
rat

などの外部コマンドに頼ることなくtac


この質問のタグを改善するための提案はありますか?
200_success

1
新しい「pure-vi」または同様のタグでしょうか?外部ツールを使用したくないという願望を示すタグから恩恵を受けるいくつかの質問を見てきました。メタでそれについて尋ねるべきですか?
ジョン・オム。

1
@Carpetsmoker(およびこれに従うことに興味のある人)のタグの質問は、metameta.vi.stackexchange.com
questions/1229/…にあります

回答:


29

グローバルの力はここで機能します:

:g/^/exe "normal ddggP"

または、もっと簡単(@tommcdoに感謝)

:g/^/move 0

最初の行はすべての行に一致し、行ごとに削除してファイルの上部に貼り付けます。ファイル内を移動すると、テキストが反転します。

2番目も同様にすべての行に一致し、ファイルの先頭に移動します。

注:これらは両方ともファイル全体で機能し、行のサブセットの反転には正しく適用されません。範囲内で機能するソリューションについては、Ingo Karkatの回答を参照してください。

説明:

gグローバルコマンドは、
/^/最初(すなわち、すべての行)を持つ任意の行と一致する
exe次の文字列を実行し
"normal、通常モードコマンドを実行し
dd、削除行の
ggファイルの先頭に移動
P現在の位置上記のペーストを

move 0 現在の行を行0の下に移動します(位置1またはファイルの最初の行に配置します)


6
:normalコマンドの代わりに、Exコマンドを使用して:move 0、行をバッファーの先頭に移動できます。
tommcdo

1
また:execute、コマンドを動的に構築する必要がある場合にのみ必要:execute 'normal' g:user_commandです。
tommcdo

@tommcdo良い点!使用する習慣があるのは:execute、既存のコマンドの後に他のExコマンドを後から追加することが多いためです:exe。後で戻って挿入するよりも、既にある方が便利です。残念ながら、この習慣はこの答えに漏れており、あまり当てはまりません。
ジョン・オム。

1
私の使用についての詳細:execute:文字列をとるので、文字列を構築していなくても、通常モードのコマンドが終了する場所を明確に描写します。<esc>またはモードを終了するものは何でも。繰り返しますが、これは個人的な好みと習慣です。:-)
ジョン・オム。

3
これは、範囲btwに対して機能します:9,11g/^/move 8。...最後の数値は、範囲の先頭から1を引いた値である必要があります(Ingoの回答から適応)。
マーティントゥルノイ

13

このワンライナー(あなたの~/.vimrc)は:Reverseコマンドを定義します; :globalパーツを直接使用することもできますが、の構文:move(範囲の開始前に行を反復的にシフトし、それによって範囲を逆にする)を覚えるのは簡単ではありません。

:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1

1
FYI読者のためとして、<line1><line2>レンジにこの作業を行うために必要とされる、すなわち::7,9Reverse(の彼らはしている機能commandではない、globalまたはmove)。単純:command! -bar -range=% Reverse :global/^/m 0うも仕事が、唯一のバッファ全体のために...
マーティンTournoij

6

Pure Vim:

:g/^/m0

説明:

によると:help multi-repeat:gその従兄弟:vは2パス方式で動作します。

最初のパスは:gすべての行が一致することをマークしますが{pattern}、2番目のパス(ファイルの最初から最後まで見かけ上実行される)はを実行し[cmd]ます。上記の使用は:g、行が処理される順序を利用します(おそらく大丈夫ですが、おそらく技術的に保証されていません)。

最初にすべての行をマークし、最初のマークされた行をファイルの先頭に移動し、2番目をファイルの先頭に移動し(前に移動した行の上)、3番目のマークされた行(再び以前に移動した上)行)、ファイルの最後の行が先頭に移動するまで続き、ファイルを効果的に反転します。

:g上から下以外の順序で行を処理した場合、このコマンドは機能しないことに注意してください。

出典:vim wikia すべての行gのべき乗を逆にします

外部コマンドを使用したいくつかの例:

  • tacGNU coreutilsの一部- cat反転):

    :%!tac                                                                                                                                                                                                                                                              
    
  • tail BSD / OSX(POSIX準拠ではない):

    :%!tail -r
    

    -r -rオプションを使用すると、入力が行ごとに逆順に表示されます。

    チェック:man tar詳細については。

その他のアイデアについては、以下を参照してください。


2
ジョンの答えであると:g/^/m0同じではありません:g/^/move 0か?
ムル

@muruそうは思いますが、これは(vim wikiaによると)短く、コマンドラインの使用例をいくつか追加した別の説明を追加しました。
ケノーブ

はい、私は他のコマンドのために賛成しました(私tacも投稿しました)。しかし、私はダウンボットが繰り返された答えのせいだと疑っています。
ムル

tacOPによって言及されたことは承知していますが、他のすべての同様の質問はとにかくこれと重複するので、再度言及するのは良いことです。ジョンはこのコマンドを@tommcdoコメントから取得しましたが、最初はDerMikeから取得しましたが、彼は単にwikiaから取得したと思うので、vim wikiaにクレジットを与えました。
ケノーブ

適切な説明が付いたはるかに短いバージョンであり、適切なソースも信用しているため、より多くの価値があります。シェルコマンドの使用は非常に簡単で便利です。人々が同意しない場合、彼らは単純に投票することができ、大したことはありません。
ケノーブ

6

機能的なVimLの精神:

:call setline(1, reverse(getline(1, line('$'))))
  • getline(1, line('$'))バッファ内のすべての行のリストを返します。 バッファの最後の行を示す'$'特別な引数ですline()
  • reverse(...)入力リストをインプレースで反転します。reverse(copy(...))入力リストを変更しない場合に使用する必要があります。
  • setline(1, ...)指定された行を2番目の引数に置き換えます。2番目の引数がリストの場合、リストの長さと同じ行数がリストのコンテンツに置き換えられます。

必要に応じて、範囲(デフォルトの%バッファー全体)を取るコマンドを定義することもできます

:command! -bar -range=% Reverse call setline(<line1>, reverse(getline(<line1>, <line2>)))

1
私はこの答えが好きです。また、他の回答のコマンドのhlsearchように(有効になっている場合)ものを強調表示しません:g/...パフォーマンスはおそらく悪いでしょうか?getline(1, line('$'))メモリ内のバッファ全体を取得するため。reverse()それは...のような非常に少ないメモリを取る必要がありますので、その場であると思われる
マーティンTournoij

3

Vimドキュメントごとusr_12.txt-巧妙なトリック

12.4行の順序を逆にする

:globalコマンドは、と組み合わせることができる:move逆ファイルで、その結果、最初の行の前にすべての行を移動するコマンド。コマンドは次のとおりです。

:global/^/m 0

略称:

:g/^/m 0

^正規表現は(ラインがブランクであっても)行の先頭にマッチします。この:moveコマンドは、一致する行を神話上の0番目の行の後に移動するため、現在の一致する行がファイルの最初の行になります。ように:globalコマンドを変更する行番号によって混乱されていない、:global最初のように、ファイル及びプットそれぞれの残りのすべての行と一致するように進みます。

これは、一連の行でも機能します。最初に最初の行の上に移動し、でマークしmtます。次に、カーソルを範囲内の最後の行に移動して、次のように入力します。

:'t+1,.g/^/m 't

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