Help us understand the problem. What is going on with this article?

Vim で表示しているテキストを外部プログラムで編集する

この記事は Vim Advent Calendar 2019 の 13 日目の記事です。

Vim は選択範囲であったり開いているテキスト全体であったりに対して、外部プログラムで編集することができます。
ここでは、 :{range}!{filter} [arg] を題材にして動きを確認していきます。

なお、詳細については :help complex-change もしくは :help filter に記載があります。

tate コマンドで縦書きに変換する

tate コマンドは、テキストを縦書きに変換するプログラムです。

$ type sample.txt | iconv -f utf-8 -t cp932
Vim で表示している

テキストを

外部プログラムで

編集する

↑ のような sample.txt に対して、 tate コマンドを使うと縦書きになります。

$ type sample.txt | tate
編 外 テ V
集 部 キ i
す プ ス m
る ロ ト  
  グ を で
  ラ   表
  ム   示
  で   し
      て
      い
      る

この動作を Vim 上で直接再現するのが filter コマンドになります。
ここでは、 :%!tate というコマンドで、テキスト全体を tate コマンドで処理してみます。

tate.gif

大体想定通りだと思いますが、 range で指定した範囲のテキストを filter で指定したプログラムの標準入力に渡し、プログラムの標準出力で出力されたテキストで置き換えることができます。

ちなみに、 tate コマンドは以下になります。

tate
https://github.com/mattn/tate

filter として使いやすいプログラム

sed / awk / Perl あたりのワンライナーで書きやすいプログラムが使いやすいです。
自分は、 Perl を良く使っていますので、いくつか例を示します。

サンプル 1 : すべて大文字化

A filter is a program that accepts text at standard input, changes it in some
way, and sends it to standard output.  You can use the commands below to send
some text through a filter, so that it is replaced by the filter output.
Examples of filters are "sort", which sorts lines alphabetically, and
"indent", which formats C program files (you need a version of indent that
works like a filter; not all versions do).  The 'shell' option specifies the
shell Vim uses to execute the filter command (See also the 'shelltype'
option).  You can repeat filter commands with ".".  Vim does not recognize a
comment (starting with '"') after the `:!` command.

:%!perl -anE "print uc($_)"

A FILTER IS A PROGRAM THAT ACCEPTS TEXT AT STANDARD INPUT, CHANGES IT IN SOME
WAY, AND SENDS IT TO STANDARD OUTPUT.  YOU CAN USE THE COMMANDS BELOW TO SEND
SOME TEXT THROUGH A FILTER, SO THAT IT IS REPLACED BY THE FILTER OUTPUT.
EXAMPLES OF FILTERS ARE "SORT", WHICH SORTS LINES ALPHABETICALLY, AND
"INDENT", WHICH FORMATS C PROGRAM FILES (YOU NEED A VERSION OF INDENT THAT
WORKS LIKE A FILTER; NOT ALL VERSIONS DO).  THE 'SHELL' OPTION SPECIFIES THE
SHELL VIM USES TO EXECUTE THE FILTER COMMAND (SEE ALSO THE 'SHELLTYPE'
OPTION).  YOU CAN REPEAT FILTER COMMANDS WITH ".".  VIM DOES NOT RECOGNIZE A
COMMENT (STARTING WITH '"') AFTER THE `:!` COMMAND.

サンプル 2 : SREC の S0 レコードをデコード

443A5C446174615C5358313231325F4150495C4150495C4150495F636F64655C が ASCII の 16 進数表記になっているので変換するという例。
Vim のコマンドラインモードでは、 % がファイル名に変換されてしまうので \% と書く必要があることに注意。

S02B0000443A5C446174615C5358313231325F4150495C4150495C4150495F636F64655C7475746F7269616C44

:%!perl -ape "s/^(S0......)((..)+)(..$)/sprintf qq'\%s\%s\%s', $1, pack('H*', $2), $3/e"

S02B0000D:\Data\SX1212_API\API\API_code\tutorial6C

サンプル 3 : 前の行のタイムスタンプとの差分を追加しつつ、 ID (3 カラム目) 毎の差分も出す

4.303006 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.413445 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.480696 1  2               Rx   d 8 00 57 00 00 00 00 00 00
4.482131 1  4               Rx   d 8 00 57 00 00 00 00 00 00
4.523533 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.634201 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.743692 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.780966 1  2               Rx   d 8 00 57 00 00 00 00 00 00
4.782392 1  4               Rx   d 8 00 57 00 00 00 00 00 00
4.853831 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.963971 1  1               Rx   d 8 00 00 00 00 00 00 00 00

:%!perl -ape "s/^/sprintf '\%.6f \%.6f ', $F[0]-$x{$F[2]}, $F[0]-$y/e; $x{$F[2]}=$F[0]; $y=$F[0]"

// 左から `ID 毎差分`、 `差分`、 `元のテキスト` を表示
4.303006   4.303006   4.303006 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.110439   0.110439   4.413445 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.480696   0.067251   4.480696 1  2               Rx   d 8 00 57 00 00 00 00 00 00
4.482131   0.001435   4.482131 1  4               Rx   d 8 00 57 00 00 00 00 00 00
0.110088   0.041402   4.523533 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.110668   0.110668   4.634201 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.109491   0.109491   4.743692 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.300270   0.037274   4.780966 1  2               Rx   d 8 00 57 00 00 00 00 00 00
0.300261   0.001426   4.782392 1  4               Rx   d 8 00 57 00 00 00 00 00 00
0.110139   0.071439   4.853831 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.110140   0.110140   4.963971 1  1               Rx   d 8 00 00 00 00 00 00 00 00

まとめ

以上のように、外部プログラムを使って簡単なテキスト編集ができました。
今回紹介したサンプルは Perl 中心ですが、他のプログラムでも同様の事が可能です。
使い慣れたプログラムでフィルタ処理をして、テキスト編集を快適にしていきましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away