具体例
country,name,sex,age
Japan,Ichiro,male,20
US,Jiro,female,10
Thailand,Saburo,male,0
を
name,age,sex,country
Ichiro,20,male,Japan
Jiro,10,female,US
Saburo,0,male,Thailand
にします
やり方
2つのコマンドを使います
VimでCSVを開いて、下のコマンドを入力しEnter
/\v^([^,]*),([^,]*),([^,]*),([^,]*)$
そうすると、下のように全ての行がハイライトされると思います
次に、下のコマンドを入力しEnter
:%s//\2,\4,\3,\1
並べ替えられました!
解説
1つ目のコマンド
/\v^([^,]*),([^,]*),([^,]*),([^,]*)$
これは文字列を検索するコマンドで、/
から後ろが検索する文字列(正規表現)です
このコマンドで使われている正規表現の意味だけ簡単に表で示します
正規表現 | 意味 |
---|---|
^ | 行の先頭 |
$ | 行の末尾 |
[^,] | , 以外の文字 |
[^,]* | , 以外の文字の並び |
() | 文字列を記憶 |
最後の()
の意味ですが、例えば今回は([^,]*)
としてるので、,
以外の文字の並びを記憶します
記憶した文字列は、1番目の()
で囲まれた文字列は\1
、2番目は\2
とすることで利用できます
CSVの各行は、,
以外の文字の並びが,
で区切られているので、検索が全ての行にヒットしました
/
の直後にある\v
は正規表現をエスケープする手間をなくすためのものです
Vimの標準では()
が文字列を記憶してくれないので、\v
なしで同じことをするためには次のコマンドを実行しないといけません
/^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$
(
と)
をいちいちエスケープしないといけないのでめんどくさいですね
2つ目のコマンド
:%s//\2,\4,\3,\1
これは置換をするためのコマンドで、例えば
:[range]s/foo/bar
とした場合は、range
の中のfoo
という文字列をbar
に置換します
今回の場合、range
は%
で、これは全ての行を表しています
foo
にあたるところは何もありませんが、ここを省略した時は直前の検索で利用したコマンドがそのまま入ります
今回の場合、下のコマンドを入力したのと同じです
:%s/\v^([^,]*),([^,]*),([^,]*),([^,]*)$/\2,\4,\3,\1
実は、最初から上のコマンド1つ実行しただけでも同じ結果になりますが、
2つに分けたのには理由があるので、後で説明します
次に、bar
の部分にあたる\2,\4,\3,\1
の\1
や\2
はそれぞれ1つ目のコマンドの()
で囲まれた文字列を指しています
例えば具体例の1行目はcountry,name,sex,age
なので\1
はcountry
、\2
はname
を指しているという具合です
全ての行に対してこの操作をしているので、無事CSVの列を並べ替えられたというわけです
コマンドを2つに分けた理由
今回は、1つ目のコマンドでは検索だけ、2つ目のコマンドで置換するというふうにしました
理由は最初に検索だけすることで、置換しようとしている範囲が意図したものになっているか確認できますし、ファイルの内容を間違って変更する心配もないからです
特に、複雑な正規表現を作る時は何回かテストするので、検索と置換の作業を分けることで、テストのたびにファイルを変更してしまうということも無くなります