CSVはよく使われるデータ形式だが、この形式がデータ交換用データの全てというわけではない。データ交換という観点から言えば最近ではJSONが使われることが多いし、XMLも多い。閲覧という観点から言えばやはりHTMLが使われることが多く、CSVデータが閲覧用にそのまま提供されるというのは少ないように思う。

CSVはデータ形式がシンプルなものなので、プログラムを使って別の形式に変換するというのがさほど難しくない。自分で厳密にCSVパーサを実装しようと思うと多少難しくなるが、CSVパーサはすでにさまざまなものが提供されているし、サードパーティ製ライブラリを使うのが面倒、または使い方がよくわからないという場合でも、簡単なスクリプトでもある程度の変換は自動で行うことができる。ただし、プログラミングをしたことがない方にとってはハードルが高いかもしれない。

そこでchrisbra/csv.vimだ。このプラグインにはCSVデータを任意のほかのフォーマットに変換するための機能が用意されている。簡単な形式であれば、この機能だけで十分だ。プログラミングが面倒だとか、やったことがない、という方にとって、この機能はかなり便利なのではないかと思う。今回はこの機能の使い方を紹介する。

CSVConvertDataでデータ変換 - HTMLへ変換

chrisbra/csv.vimには「CSVConvertData」という機能が用意されている。この機能はレコード(行)単位でCSVデータを任意のテキストデータへ変換するというものだ。全データの最初と最後に任意の文字列を付加することができ、結果としてほかのフォーマットへの変換が行われることになる。

例えば、次のCSVデータをHTMLへ変換する例を考える。

変換元のCSVデータ(日本郵政提供の住所データ)

CSVConvertDataを実行する。

CSVConvertDataを実行

CSVConvertDataを実行すると、次のように「Pre convert text: 」というプロンプトが表示される。全データの最初に付与する文字列を指定せよ、という意味だ。

全データの前に付ける任意の文字列を求められる

HTMLのテーブルデータに変換しようと思うので、ここで次のように「<html><body><table>」と入力する。変換後全データの先頭にこの文字列が追加されることになる。

HTMLとテーブルとしてのタグを入力

次は逆に全データ変換後に最後に付与する文字列の入力を次のように求められる。

全データの後ろに付ける任意の文字列が求められる

テーブルとHTMLを閉じたいので、先程入力したタグに対応する終了タグ「</table></body></html>」と入力する。

テーブルとHTMLを閉じるタグを入力

変換としてはここからが本題だ。次のように、各レコード(各行)をどのような文字列へ変換するのか指定するモードになる。

レコードをどのように変換するのか指定

ここでは「<tr><td>%s</td><td>%s %s %s</td></tr>」と入力する。ポイントは「%s」だ。この文字列はセルの値に置換される。1つ目の%sは1列目の値へ、2つ目の「%s」は2列目の値へ、といった感じだ。つまり、使いたいデータを1列目から順番に並べておく必要がある。列の移動に関してはこれまでに操作方法を説明してあるので、その操作で入れ替えを行って操作してもらえればと思う。

レコード(行)をどのようなフォーマットに変換するのかを指定

変換を実施すると、次のように変換後のデータが別ウィンドウで表示される。プログラムを組むことなくここまでできるのだから簡単なものだ。

変換後のHTMLデータ

ただし、上記スクリーンショットからわかるとおり、この方法だとデリミタ(区切り文字)も含まれているほか、ダブルクォーテーションも含まれていて、閲覧用データとしては扱いにくい。もうちょっと実用的なデータに変換していこう。

CSVConvertData!でデータ変換 HTMLへ変換

CSVConvertDataにはビックリマークを指定した「CSVConvertData!」というバージョンが用意されている。CSVConvertData!はデリミタを変換後データに含めないというもので、用途によってはこちらのほうが便利ではないかと思う。

まず、Vimの置換機能を使ってダブルクォーテーションを削除する。

置換機能でダブルクォーテーションを削除

CSVConvertData!を実行する。

CSVConvertData!を実行

先ほどと同じようにPre、Post、変換内容を指定する。

Pre convert text:を入力

Post convert text:を入力

変換内容を入力

生成されるHTMLデータは次のようになる。最初に変換した内容よりも実用的な形式になっていることがわかる。

変換後のHTMLデータ 改善版

Webブラウザで閲覧すると次のようになる。シンプルだが見える形式には仕上がっていることがわかる。

Webブラウザで閲覧

このように簡単なデータ変換であればCSVConvertData!を使って実施できる。CSVConvertData!の使い方がすでに簡単なスクリプトというかプログラミングとも言える。プログラミングをしたことがない方は、こういった作業を通じてプログラミングに慣れていくとよいだろう。

chrisbra/csv.vimのポテンシャルの高さ

プラグインのメタプラグイン経由でインストールしたchrisbra/csv.vimだが、このプラグインのポテンシャルの高さは伝わったのではないだろうか。閲覧から編集、分析、フィルタリング、データ変換まで、chrisbra/csv.vimを使うことでさまざまな操作を実地することができる。

CSVデータのような形式のデータをVimで操作することができる、というのは、Vimの活用シーンを広げる大きなきっかけになるはずだ。最初は「使いにくい意味不明なエディタ」という印象だった方も多いかもしれないVimだが、そのうちVimの強力さや便利さが伝わって利用頻度が上がっていく。そして今回のケースのようにCSVデータ専用のアプリケーションとしても利用できることがわかる。Vimに限らずプラグインを使うと、エディタというポジションから特定のデータを操作するための専用アプリケーションという側面まで出てくる。使えば使うほど便利になっていくエディタなのだ。

Linuxの管理においてエディタは切っても切り離すことができない。そして、エディタは管理のみならずLinuxを利用するユーザーという立場からしても欠かすことのできないアプリケーションだ。Vimの活用はそのままLinuxの活用に直結している。ぜひともここでVimスキルを引き上げていってもらえればと思う。

本連載で使っている~/.vimrcファイル

本連載で使っている設定ファイル(~/.vimrc)は以下の通りだ。

"dein Scripts=============================
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=~/.cache/dein/./repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('~/.cache/dein/.')
  call dein#begin('~/.cache/dein/.')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/./repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here
  call dein#add('junegunn/seoul256.vim')
  call dein#add('vim-airline/vim-airline')
  call dein#add('vim-airline/vim-airline-themes')
  call dein#add('preservim/nerdtree')
  call dein#add('tpope/vim-commentary')
  call dein#add('tpope/vim-fugitive')
  call dein#add('fholgado/minibufexpl.vim')
  call dein#add('dense-analysis/ale')
  call dein#add('junegunn/fzf', {'build': './install --all'})
  call dein#add('junegunn/fzf.vim')
  call dein#add('sheerun/vim-polyglot')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif

" seoul256
let g:seoul256_background = 233
colo seoul256

" vim-airline
let g:airline_powerline_fonts = 1
let g:airline_theme = 'molokai'

" NERDTree
"  <C-o> open NERDTree
nnoremap <silent> <C-o> :NERDTreeToggle<CR>

" minibufexpl
nnoremap <silent> bn :<C-u>:bnext<CR>
nnoremap <silent> b1 :<C-u>:b1<CR>
nnoremap <silent> b2 :<C-u>:b2<CR>
nnoremap <silent> b3 :<C-u>:b3<CR>
nnoremap <silent> b4 :<C-u>:b4<CR>
nnoremap <silent> b5 :<C-u>:b5<CR>
nnoremap <silent> b6 :<C-u>:b6<CR>
nnoremap <silent> b7 :<C-u>:b7<CR>
nnoremap <silent> b8 :<C-u>:b8<CR>
nnoremap <silent> b9 :<C-u>:b9<CR>

" fzf
nnoremap <silent> fzf :Files<CR>
nnoremap <silent> ls :Buffers<CR>

"End dein Scripts=========================

set number
syntax on
set whichwrap=b,s,[,],<,>,~,h,l
set cursorline
set incsearch
set hlsearch
set ignorecase

付録 chrisbra/csv.vim 操作・設定方法まとめ

コマンド 内容
CSVWhatColumn カーソルが何列目にあるか
CSVWhatColumn! 同列1行目の内容を表示
CSVNrColumns 最大列数を表示(先頭から10行で判断)
CSVSearchInColumn /パターン/ 現在の列をパターンで検索
CSVSearchInColumn 列番号 /パターン/ 指定した列をパターンで検索
CSVHiColumn 現在の列を強調表示
CSVHiColumn 列番号 指定した列を強調表示
CSVHiColumn! 列の強調表示を解除
CSVArrangeColumn テーブル形式での表示へ切り替え(実験的機能)
CSVTabularize テーブル形式でのプレビュー表示
CSVDeleteColumn 現在の列を削除
CSVDeleteColumn 列番号 指定した列を削除
CSVHeader 1行目を別ウィンドウで表示
CSVHeader 行数 先頭から指定行数分を別ウィンドウで表示
CSVHeader! 開いた行ヘッダウィンドウを閉じる
CSVVHeader 1列目を別ウィンドウで表示
CSVVHeader 列番号 行頭から指定列数分を別ウィンドウで表示
CSVVHeader 開いた列ヘッダウィンドウを閉じる
CSVSort 現在の列でファイルをソート
CSVSort 列番号 現在の列でファイルをソート
CSVSort! 現在の列でファイルを逆順にソート
CSVSort! 列番号 現在の列でファイルを逆順にソート
CSVColumn 現在の列をコピー
列番号CSVColumn 指定した列をコピー
CSVMoveColumnor 現在の列を最後の列の右側へ移動
CSVMoveColumn 列番号 列番号 最初に指定した列を、2つ目に指定した列の右側へ移動
CSVSumCol 現在の列の合計を出力
CSVSumCol 列番号 指定した列の合計を出力
CSVSumRow 行の合計を出力
CSVNewRecord 新しい行を作成
CSVNewDelimiter デリミタ 区切り文字を変更
CSVConvertData データをほかの形式に変換
CSVDuplicates 列番号 指定した列で重複している行を出力
CSVAnalyze 現在の列を分析する(値とその数、割合など)
CSVAnalyze 列番号 指定した列を分析する(値とその数、割合など)
CSVVertFold 1列目から現在の列を折りたたむ
CSVVertFold 列番号 1列目から指定した列までを折りたたむ
CSVVertFold! 列の折りたたみを解除する
CSVTranspose 列と行を入れ替える(転置)
CSVAddColumn 現在の列の右側に新しい列を追加
CSVAddColumn 列番号 指定した列の右側に新しい列を追加
CSVDupColumn 現在の列を右側に複製
CSVDupColumn 列番号 指定した列を右側に複製
CSVSubstitute 列番号/パターン/文字列/ 指定した列で置換
CSVColumnWidth 列ごとの最大文字数を出力
CSVCountCol 現在の列内の値の数を出力
CSVCountCol 列番号 指定した列内の値の数を出力
CSVMaxCol 現在の列内の最大値を出力
CSVMaxCol 列番号 指定した列内の最大値を出力
CSVMinCol 現在の列内の最小値を出力
CSVMinCol 列番号 指定した列内の最小値を出力
CSVAvgCol 現在の列内のデータの平均値を出力
CSVAvgCol 列番号 指定した列内のデータの平均値を出力
PopVarCol 現在の列の母集団分散を出力
PopVarCol 列番号 指定した列の母集団分散を出力
SmplVarCol 現在の列の標本分散を出力
SmplVarCol 列番号 指定した列の標本分散を出力
PopStdCol 現在の列の母標準偏差を出力
PopStdCol 列番号 指定した列の母標準偏差を出力
SmplStdCol 現在の列の標本標準偏差を出力
SmplStdCol 列番号 指定した列の標本標準偏差を出力
移動キー 内容
Ctrl-→ 右の列へ移動
L 右の列へ移動
W 右の列へ移動
Ctrl-← 左の列へ移動
E 左の列へ移動
H 左の列へ移動
列を上へ移動
K 列を上へ移動
列を下へ移動
J 列を下へ移動
フィルタキー 内容
↩️ 現在の列と一致しないすべての行を動的に折りたたむ
Space 現在の列と一致するすべての行を動的に折りたたむ
BS 動的フィルタから最後のアイテムを削除
設定項目 内容
g:csv_delim デフォルトのデリミタ
g:csv_no_conceal 1に設定するとデリミタ部分を|で視覚的に表示(デフォルトは設定されていない)
g:csv_highlight_column ‘y’に設定するとカーソルがある列を自動でハイライト
b:csv_headerline ヘッダの行数を指定。0を指定するとヘッダとしてのハイライトが行われなくなる