Vimで数字を増減して連番を振る(Ctrl-a / Ctrl-x / g Ctrl-a)
VimのノーマルモードでCtrl-aを押すと、カーソル付近の数字が1増えます。Ctrl-xなら1減ります。ビジュアルモードで複数行を選んでからg Ctrl-aを押せば、1, 2, 3と連番が振れます。ここまでは数秒で覚えられる機能ですが、2026-10-06の末尾でCtrl-aを押すと2026-10-05になります。増やしたつもりが減っています。
原因は-06を「マイナス6」と読んでいることで、数字の読み方を決めているのがnrformatsというオプションです。この記事では、基本の増減と連番の振り方を押さえたうえで、日付が減る件と007が010になる件を、VimとNeovimの両方で実際に押して確かめた結果から直します。
検証環境:Vim 9.1.1752(macOS同梱の/usr/bin/vim)とNVIM v0.12.4。一時ディレクトリでtmuxの中にVim/Neovimを対話起動し、キーを送ってから画面を読み取る手順で確かめました。既定値の比較は、-u NONEでの起動、~/.vimrcがある状態での起動、defaults.vimだけを読ませた起動の3通りです。記事中の変化前と変化後の値はすべてその実行結果です。
目次(9項目)
Ctrl-aとCtrl-xはカーソルより右の最初の数字に効く
Ctrl-aとCtrl-xの対象は「カーソルの位置か、それより右にある最初の数字」です。カーソルが数字の上に無くても構いません。abc 10 def 20という行の先頭でCtrl-aを押すとabc 11 def 20になり、defのdの上で押すと、右側の20が21になります。カーソルは変化した数字の末尾へ移ります。
数字の途中にカーソルがあっても、数字全体が1つの値として扱われます。abc 123の2の上で押した結果はabc 124で、2だけが3になるようなことはありません。逆に、カーソルより右に数字が1つも無ければ何も起きません。abc 10 def 20 xyzのxyzの上で押してもビープが鳴るだけで、左の20には戻ってくれません。
回数を前に付けると、その数だけ加減します。5Ctrl-aで10が15になります。続けて.を押すと回数ごと繰り返されるので、もう5増えて20になりました。足し算そのものより複雑な計算が要るなら、expressionレジスタ「=」で計算結果を挿入する方法のほうが向いています。
| キー | 動作 | 例(変化前→変化後) |
|---|---|---|
| Ctrl-a | 右の最初の数字を1増やす | abc 10→abc 11 |
| Ctrl-x | 右の最初の数字を1減らす | abc 10→abc 9 |
5Ctrl-a | 5増やす | abc 10→abc 15 |
| g Ctrl-a | 選択した行に連番を足す(ビジュアルモード) | 0 0 0の各行→1 2 3 |
g Ctrl-aで連番を振る(行選択と矩形選択)
連番を作るときは、まず同じ数字を並べておきます。0. aから0. dまでの4行をVで選び、g Ctrl-aを押すと1. 2. 3. 4.になりました。1行目に1、2行目に2と、上から順に足す量が1ずつ増える仕組みです。全部1.で並べていた場合は2.から6.になるので、1から始めたいなら0で並べるのが手っ取り早い方法です。
同じ選択でgを付けずにCtrl-aだけを押すと、全行に同じ1が足されます。1.が5行並んでいれば、全部2.になって終わりです。「連番にならない」という相談はたいていこの取り違えで、gの有無が「全行に同じ数」と「行ごとに増える数」の違いになっています。
1行に数字が複数ある場合は、行の中で最初に見つかった数字だけが変わります。id=0 v=10を4行並べてVで全行を選びg Ctrl-aを押すと、id=1からid=4になり、v=10は手つかずでした。右側の10のほうに番号を振りたいなら、Ctrl-vの矩形選択で10の桁だけを囲みます。10を囲んでg Ctrl-aを押すとv=11からv=14になり、id=0は残りました。
矩形選択には注意点があります。数字の一部だけを囲むと、囲んだ部分だけを数字として読みます。v=19の9だけを囲んでCtrl-aを押した結果はv=20ではなくv=110でした。9を10に置き換えたので、前の1とつながって110に見えています。桁数の違う数字が混ざった列を矩形で選ぶときは、いちばん長い数字の頭から末尾まで囲むようにしてください。
刻み幅を変える(3g Ctrl-a)と、途中から振り直すとき
g Ctrl-aの前に回数を付けると、それが刻み幅になります。0が4行並んだところで3g Ctrl-aを押すと3 6 9 12でした。10刻みの行番号や、5分刻みの時刻の分のような列を作るときに使えます。Ctrl-xにもg Ctrl-xがあり、こちらは下の行ほど多く引きます。
番号付きのリストに1行差し込んだときの振り直しには、行ごとに増えない普通のCtrl-aのほうが合っています。1. a 2. bのあとに3. newを足すと、元の3. c 4. d 5. eと番号がずれます。3. cの行から最後までをVで選んでCtrl-aを1回押すと、4. c 5. d 6. eになり、1から6まで並び直しました。すでに連番になっている範囲に同じ数を足すだけなので、gは要りません。
g Ctrl-aのあとに.を押すと同じ範囲にもう一度連番が足されます。1から4にしたあとで.を押したら2 4 6 8になりました。うっかり押すと崩れるので、連番を振ったあとの.には気をつけたほうが安全です。行ごとに違う加工まで要る場合は、マクロで複雑な繰り返し作業を自動化する方法と組み合わせると、Ctrl-aをマクロの中で使って1行ずつ番号を進められます。
日付でCtrl-aを押すと数字が減る理由
冒頭の現象をもう一度見ます。Neovim 0.12.4を設定なしで起動し、2026-10-06の末尾にカーソルを置いてCtrl-aを押すと2026-10-05になります。数字の直前にある-を負の符号として読み、-6に1を足して-5にしているためです。Vimでもnrformatsをbin,hexにした状態なら同じく2026-10-05になりました。
負の数として読むかどうかは、-の前に何があるかを見ていません。x-06でもa -06でも、行頭の-06でも、Neovimの既定ではすべて-05方向に動きました。9-2020でCtrl-xを押すと9-2021、Carbon-14でCtrl-aを押すとCarbon-13と、ハイフンでつないだ型番やバージョン表記はどれも逆向きに動きます。
日付の場合はさらに、月や日の先頭の0が絡みます。macOS同梱のVimで~/.vimrcを置いて起動すると、2026-10-06は2026-10-07に増えました。直ったように見えますが、これは06を8進数として読んだ結果で、8進数には符号を付けないので増えているだけです。同じVimで2026-10-07は2026-10-010(8進数の7の次は10)、2026-10-08は2026-10-7になりました。08は8進数として成り立たないので10進数の-8に戻り、そのうえ先頭の0まで落ちています。日によって結果が変わるので、たまたま増えた日に試すと問題に気づけません。
nrformatsのunsignedとblankの違い
nrformatsには負の符号の扱いを変える値が2つあります。unsignedは-を一切符号と見なしません。blankは、-の直前が空白か行頭なら負の数、文字がくっついていれば符号ではない、と前の文字で判断します。:help 'nrformats'の例がそのまま違いを表していて、Carbon-14は両方ともCarbon-15になりますが、空白をはさんだCarbon -8でCtrl-xを押すと、blankでは-9、unsignedでは-7に分かれます。
VimとNeovimの両方で、bin,hexに足した場合の結果を並べました(両者で結果は同じでした)。
| 行(押したキー) | bin,hex | +blank | +unsigned |
|---|---|---|---|
2026-10-06(Ctrl-a) | 2026-10-05 | 2026-10-07 | 2026-10-07 |
9-2020(Ctrl-x) | 9-2021 | 9-2019 | 9-2019 |
Carbon-14(Ctrl-a) | Carbon-13 | Carbon-15 | Carbon-15 |
Carbon -8(Ctrl-x) | Carbon -9 | Carbon -9 | Carbon -7 |
x = -5(Ctrl-a) | x = -4 | x = -4 | x = -6 |
0(Ctrl-x) | -1 | -1 | 0 |
差が出るのは下の3行です。unsignedはx = -5のような本物の負の数でも-を無視するので、Ctrl-aで絶対値が増えて-6になります。0から下にも行かず、0のまま止まります。コードの中の負の定数をいじることがあるなら、空白の有無で見分けるblankのほうが期待どおりに動きます。日付・型番・バージョンのようにハイフンが文字にくっつく表記はblankでも全部正の数として扱われるので、日付の問題はこれで解決します。
blankはVimのヘルプでは9.2の変更点一覧に載っている比較的新しい値です。手元のVim 9.1.1752とNeovim 0.12.4では使えましたが、それより古い版では確かめていません。:set nrformats+=blankがエラーになる環境なら、代わりにunsignedを足すのが次善の手です。
007が010になるoctalと、Vim・Neovimの既定値の違い
もう1つの罠がoctalです。これがnrformatsに入っていると、0で始まる数字を8進数として読みます。007でCtrl-aを押すと、8進数の7の次なので010になります。連番のファイル名やゼロ埋めのIDを増やそうとして10番台に飛んだら、まずこれを疑います。
厄介なのは、既定値が起動のしかたで変わることです。Vimのnrformatsの既定値はbin,octal,hexで、octalを外しているのはdefaults.vimのset nrformats-=octalの1行です。ところがdefaults.vimはユーザーのvimrcが見つからないときにしか読まれません(:help defaults.vim)。つまり~/.vimrcを1行でも書いた時点でoctalが戻ってきます。実際、set numberだけの~/.vimrcを置いて起動したVimで007は010になりました。macOS同梱のVimは、システムのvimrcがskip_defaults_vimを立てているので、~/.vimrcが無くてもoctal入りでした。
| 起動のしかた | nrformats | 007でCtrl-a |
|---|---|---|
Vim(-u NONE) | bin,octal,hex | 010 |
Vim(~/.vimrcあり) | bin,octal,hex | 010 |
Vim(defaults.vimだけを読ませた) | bin,hex | 008 |
| Neovim 0.12.4(設定なし) | bin,hex | 008 |
Neovimは既定値そのものがbin,hexなので、設定ファイルの有無に関係なく008になります。octalが無いときは先頭の0を桁埋めとして扱い、0099は0100と4桁を保ちました。今の値は:set nrformats?で確かめられます(:set と :set all の違いも参照)。macOS同梱のVimで出た表示は次のとおりです。
:set nrformats?
nrformats=bin,octal,hex
日付の問題とまとめて直すなら、octalを外してblankを足した値を書いておきます。macOS同梱のVimでこの値にすると、2026-10-07は2026-10-08、2026-10-09は2026-10-10と、ふつうの日付として増えました。
" ~/.vimrc
set nrformats=bin,hex,blank
-- init.lua
vim.o.nrformats = "bin,hex,blank"
+=ではなく=で丸ごと指定しているのは、起動のしかたで既定値が違っても結果をそろえるためです。nrformatsはバッファごとの値なので、ファイルタイププラグインが書き換えている場合は:verbose set nrformats?で出どころを見てください。
16進数・2進数・英字(alpha)の増減
hexとbinは両方の既定値に入っているので、何もしなくても0xや0bで始まる数字はその進数で増減します。0x0fでCtrl-aを押すと0x10、0xffは0x100、0x100でCtrl-xは0x0ffと、桁数を保って3桁で返ってきました。英字の大文字小文字も保たれ、0xFEは0xFF、0xfeは0xffになります。2進数は0b101が0b110、0b1000から1引くと0b0111でした。
alphaを足すと、1文字の英字も増減の対象になります。:set nrformats+=alphaのあとa)でCtrl-aを押すとb)になり、a), b), c)の箇条書きに使えます。z)やZから先へは進まず、aからCtrl-xでも戻らず、端で止まります。
ただしalphaは常用には向きません。「カーソルより右の最初の対象」に英字が含まれるので、abc 10の行頭でCtrl-aを押すとabc 11ではなくbbc 10になりました。数字が英字より先にある10 abcなら11 abcです。普段の数字の増減を壊すので、必要なときだけ:setlocal nrformats+=alphaで足して、終わったら外すくらいが扱いやすいです。
検証でいちばん驚いたのは、macOS同梱のVimで日付の値を1日ずつ変えて試したときの結果です。06から07は普通に増えたので「Vimなら減らない」と一度メモに書いたのですが、次に07で押したら010が出てきて、その次の08は7に減ったうえに0が消えました。同じキーを同じ場所で押しているのに、日付の値によって増えたり減ったりします。Neovimで先に試していたら「必ず減る」で済んでいた話なので、エディタと日付の組み合わせを1つだけ試して結論を出していたら、間違った記事を書いていたと思います。
まとめ
Ctrl-aとCtrl-xはカーソルより右の最初の数字に効き、ビジュアルモードではCtrl-aが全行に同じ数、g Ctrl-aが行ごとに増える数を足します。刻み幅はg Ctrl-aの前の回数で決まります。数字が思った向きに動かないときは、nrformatsが数字をどう読んでいるかを疑うのが近道です。連番がうまく作れないときに見る場所を表にしておきます。
| 症状 | 原因 | 対処 |
|---|---|---|
| 全行が同じ数になる | gを付けていない | 選び直してg Ctrl-a |
| 右側の数字が変わらない | 行の最初の数字だけが対象 | Ctrl-vで数字の列だけ囲む |
19が110になる | 矩形が数字の途中から | 数字の頭から囲む |
| 日付や型番で減る | -を負の符号と読む | nrformatsにblank |
007が010になる | octalが入っている | nrformatsからoctalを外す |
| 英字が増える | alphaが入っている | 使い終わったら外す |
行ではなく画面上の複数箇所を同時に書き換えたいなら、Neovimのマルチカーソルのほうが合う場面もあります。番号を振る作業に限れば、0を並べてg Ctrl-a、nrformatsはbin,hex,blank、の2つを覚えておけば足ります。