vim中寄存器使用和vim标记。 - rainysia的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/rainysia/article/details/7721691
一:官方帮助手册
:help registers
:help :registers
二: 寄存器分类
1.无名(unnamed)寄存器:"",缓存最后一次操作内容;
2.数字(numbered)寄存器:"0 ~ "9
,缓存最近操作内容,复制与删除有别, "0寄存器缓存最近一次复制的内容,"1-"9缓存最近9次删除内容
3.行内删除(small delete)寄存器:"-,缓存行内删除内容;
4.具名(named)寄存器:"a ~ "z
或"A - "0Z
,指定时可用;
5.只读(read-only)寄存器:":, "., "%, "#
,分别缓存最近命令、最近插入文本、当前文件名、当前交替文件名;
6.表达式(expression)寄存器:"=
,只读,用于执行表达式命令;
7.选择及拖拽(selection and drop)寄存器:"*, "+, "~
,存取GUI选择文本,可用于与外部应用交互,使用前提为系统剪切板(clipboard)可用;
8.黑洞(black hole)寄存器:"_
,不缓存操作内容(干净删除);
9.模式寄存器(last search pattern):"/
,缓存最近的搜索模式。
三:查看寄存器内容
:reg 查看所有寄存器内容
:reg 寄存器名 查看单个寄存器内容 比如 :reg _ :reg * :reg 1 :reg 9 :reg a 等等
数字寄存器,也是最常用的 从0-9。 如果不指定寄存器的名字,那么删除的内容,vim默认是存到 1 ,复制内容是存到 0 号寄存器。 如果继续删除,那么原来 1 的内容就转到 2,类推,当删除超过9的时候, 原先的 8号数字寄存器就转到9, 原先9的数字寄存器内容就会丢失。
实验1:
先在vim里面输入1-0 10个数字,每个数字一行,接着从0 9 8 7 6 5 4 3 2 依次dd删除,然后:reg查看寄存器,接着yy复制数字1的这行,可以看见"0 寄存器 的值是1
“1 ~ ”9 寄存器依次是 2~0
使用p来粘贴,如果最近一次操作是复制,那么p就会添加 “0 寄存器的内容,如果最近一次操作是删除那么就添加 "1 寄存器的内容 ,如果要粘贴其它数字寄存器的内容,
使用 "?p 来粘贴,比如要粘贴 “2 寄存器里面的,则在vim命令模式下 输入 "2p 就可以取出“2寄存器里面的内容了
其他的寄存器都是通过 "?p 来访问使用的。
具名寄存器(字母寄存器),也就是名称是单个英文字母, "a "b "c ,....,"z , 使用时,在复制或者删除命令 y 或者 d 时,在前面加上字母寄存器的字母名称就可以了, 或者是直接在删除或者复制命令后 加上字母寄存器的字母 比如 :y n 就是复制当前行到 “n 字母寄存器 :5,10y m 复制5到10行内容到 “m 字母寄存器
:pu! n 将字母寄存器 “n的内容粘贴到当前行之前 也可以使用 "mP 效果一样
:p n 粘贴字母寄存器 ”n 的内容到当前行的下一行 也可以使用 "np 效果一样
(命令模式下 :y :d :pu 分别是复制 删除 和粘贴
一般模式下 "寄存器名y “寄存器名d "寄存器名p 代表着复制 删除 和 粘贴 )
实验2:
"ayy 就是复制当前行到 "a 字母寄存器中
"b3yy 复制当前行和下面2行 到 “b 字母寄存器
“ap 粘贴 “a 字母寄存器的内容
“cd2l 向右删除2个字符 并且把内容存到 字母寄存器 “c 中 “cp 粘贴 ”c 字母寄存器里面的内容
”d3dd 删除当前行和下面2行 并且把内容存到 字母寄存器 “d 中
“fdf. 删除当前位置到句号 并且把内容存到 字母寄存器 “f 中
“gd'c 删除当前位置到标记c位置 并且把内容存到 字母寄存器 “g 中
同一个字母的大写和小写表示的是同一个寄存器,但是行为会不同,字母寄存器的名称大写时,当使用大写的寄存器进行复制或者删除文本时,原先的字母寄存器中的内容会被保留,刚删除或复制的内容则附加到原来字母寄存器内容的后面。 字母寄存器只有在指定时才被使用。
无名寄存器 "" 保存最近一次复制或删除的文本。就是p命令默认使用的寄存器。
短删除寄存器 "- (The small delete register)。事实上刚删除的文本并不一定被送到数字寄存器,如果删除的文本不含换行符(不足一整句)则文本被送至这个寄存器。如x、d2h这两条命令删除的文本都会被送到这个寄存器。注意下在这条命令虽然删除了一整行的文本但因不含换行符所以也被送到这个寄存器`0d$‘。
只读寄存器 ": ". "% "# 它们分别用来保存最近一次在命令行窗口使用的命令、最近一次插入的文本、当前编辑的文件名、当前的替代文件名。
表达式寄存器 "=
选择与拖放的寄存器"* "+ "~ 在Windows中这几个寄存器就是剪贴板。在Linux中它们也是剪贴板——但这几个寄存器是有所区别的。
黑洞寄存器 "_ 删除操作会影响现有数字寄存器的内容。前一个数字寄存器的值传给后一个数字寄存器,"9的内容被丢弃,新删除的文本则放入"1。这至少有两个直接的影响,一是"9的内容被丢弃;二是寄存器中文本的位置都发生了变化。而复制操作会改变"0的值。如果你不希望删除或复制的操作影响数字寄存器的话就使用这个寄存器。使用这个寄存器进行删除或复制的内容都会被丢弃——这还可以提高一点速度节省一点空间。
搜索式样寄存器 "/ 保存上一次搜索所使用的式样。注意这也包括了s命令中所使用的搜索式样。
寄存器有26个字母寄存器可以使用;可以使用大写字母将文本附加到已有内容后。如果在你关闭文件之前还没想到这将这些内容贴在哪里也没关系,
用`:wviminfo my_viminfo‘命令。下一次编辑时输入`:rviminfo! my_viminfo‘或者在命令行用这个命令运行`gvim -i my_viminfo myfile‘,:reg看寄存器的内容都在的。
四 。寄存器是个变量——特殊的变量,只要在前面加上一个@号就可以用变量的方式访问寄存器。
" 给寄存器赋值
let @e="开始\<CR>"
let @E="结束"
echo @e
开始
结束
" 将寄存器作为表达式的一部分
let my_var=@a . @c
" 和
echo @e+4
" 清空寄存器。
" 注意:不能用unlet清除寄存器。
:let @e=""
在编辑窗口与命令窗口间交换内容
编辑窗口的文本可以放进寄存器。搜索式样和上一条Ex命令被放进了只读寄存器"/和":。
已知寄存器的内容可以在贴到编辑窗口。可以在命令窗口作为变量使用。那有没有办法在命令窗口插入寄存器的内容呢?有没有办法在搜索式样中插入寄存器的内容呢?
比如,假设在寄存器e中保存着一个文件名:“这是一个保存在寄存器中的很长的文件名.txt”。而我想使用:w命令保存一个当前编辑文件的副本——使用寄存器e中的那个文件名。如果使用`:w @e‘的话,文件名将是“@e”而不是“这是一个保存在寄存器中的很长的文件名.txt”。这时该怎么办呢?考虑到寄存器也是变量,我们可以使用寄存器的传统办法。
" 方法一。使用:execute命令
" 写入以"e为名的寄存器中
:exe "w " . @e
那搜索呢?如果我们要在搜索式样中使用寄存器的内容呢?对于s命令的搜索式样上面的:exe大法仍然适用,但如果只是普通的搜索操作(在一般模式中按/)呢?我们要用到组合键Ctrl-R,用Vim的写法就是<C-R>。
" 方法二。使用Ctrl-R转义。
" 搜索寄存器e的内容。<Ctrl-R>表示用户在这里按了组合键Ctrl-R——不要直接输入<Ctrl-R>这8个字符。
/<Ctrl-R>e/
使用<C-R>的方式可适用于各种输入的环境中:在插入模式输入时、在命令窗口输入时、在搜索时。在插入模式时要输入寄存器内容并不需要退回到一般模式再使用p指令,可以直接按`<Ctrl-R>e‘当然e可以改成相应的寄存器名。在命令窗口与搜索时也是一样:按Ctrl-R输入寄存器名。
提示:除了一些不接受变量作为参数,不能使用寄存器名称的情况外,还有一些情况也要求插入寄存器的内容。有时我们插入寄存器的内容而不使用寄存器变量是因为我们可能还需要手工对寄存器的内容进行一些编辑。
无名寄存器总是保存着最近一次复制或删除的内容。不带寄存器名地使用p就可以添加该寄存器的内容到当前位置了。但是既然“无名”该怎么在命令窗口使用这个存器呢?又怎么插入无名寄存器的内容呢?答案是使用@",插入也是一样按Ctrl-R再按输入"就可以了。
现在总结一下:":保存了上一条Ex命令。"/保存了上一条搜索式样。字母寄存器及数字寄存器中可以保存编辑的文本。并且我们也可以在不同的环境中插入寄存器的内容。通过寄存器我们可以方便地在命令窗口编辑窗口以及搜索中交换内容。相对而言一般的变量就没这么方便,你只能在命令行中使用变量也只能是命令行中给变量赋值。
在buffer之间及程序之间交换内容
寄存器是全局的变量。在Vim中打开的所有文件2,共享这些寄存器。你可以在不同的文件之间交换内容。
通过寄存器"*和"+,Vim可以与其他程序交换信息。在Windows中这两个寄存器是一样的。在Linux中这两个寄存器则有所不同。
:help gui-selections
:help x11-selection
寄存器可以做为宏
跟一般的变量相比寄存器还有一个最大的特点就是寄存器本身可以做为宏使用。如果你有用过一般模式命令q的话就会发现q录制的击键序列就是存在寄存器中的,并且可以直接使用寄存器执行命令。现在做做实验,新建一文档随便输入几行文字。输入:
qeggddq
上面这条命令录制了一个宏并保存到寄存器e中。这个宏的作用是回到第一行并删除该行。现在看一下寄存器的内容:
:reg e
就是你刚才的键盘命令ggdd。要运行刚录制的键盘操作在一般模式输入@e就可以运行了,输入3@e会将前三行删除。
当然你不一定要用q来录制宏——因为寄存器也是变量。
:let @e="/删除本行/^Mdd:w^M"
@e
上面的^M表示的是回车键。可不是输入^再输入M,而是输入Ctrl-V(Windows是Ctrl-Q)再按回车键这时就会出现^M表示这是一个回车键。常见的还有^[表示的是<ESC>键。输入的方法也是一样按Ctrl-V再按Esc键。这样输入控制字符的方式是传统的Vi方法。在Vim中也支持用按键名表示这些控制字符。比如<CR>表示回车键3所以上面的命令也可表示为:
:let @e="/删除本行/\<CR>dd:w\<CR>"
这里一定要用双引号,我们在“脚本”一篇中已经讲到了,在单引号中的字串会被当成普通字串。后面这种表示控制字符的方式与'cpoptions'的设置有关,虽然在默认情况下都是可行的但是建议使用第一种方式。不过为了更好的可读性在教程中我们还是可能使用后面这种方式表示控制字符。
正因为寄存器可以直接执行所以":可以用来执行上一条在命令窗口使用的命令:
:@:
记得最后要按回车执行。当然现在由于命令行的历史功能这种用法没有什么实用价值。
在重定向命令中使用
重定向命令(:redir)是一个较常用的技巧。所有的字母寄存器、@*、无名寄存器(@")都可以在重定向命令中使用。还是用个例子说明好了:
假设你的小说家朋友寄了一本小说的初稿给你,但显然他没有整理文本的习惯——好消息是他这次竟然没用Word写。在你往下看之前你决定先将文档做适当的整理。使用Vim作这种事当然是小菜一碟,只用了10分钟你就将他的小说整理成一份格式整齐的文档了。
第六章 为山九仞
===============
小明是从不在午时之前离开被褥的,今天却是个例外。他一夜没睡不
过他却觉得精神比任何时候都好……
< 省略800行 >
……
第七章 功亏一篑
===============
小明已经很久没像今天这样开心了。从那时到现在已有二十年又一天
了。对他来讲二十年并不长,能在二十年又三天之内报仇已经是出乎
自己意料了。何况对方是可是威峦镖局的大当家。想到这里他的眼睛
眯得更小了……再过两天……只要两天!
但你发现这份初稿没目录,而你看小说的习惯是从目录看起。于是你决定整理一份目录。于是你用了寄存器:
:let @a=""
:g/^第.\{1,3}章 /y A
这两条命令将所有章的标题放到寄存器A中。你可以在需要目录的地方"ap。不过你还想在每章标题后加上该章对应的行号,你知道这时可以用:redir:
:redir @a
:echo "目录:"
:g/^第.\{1,3}章 /echo getline(".") . "\t\t\t" . line(".")
:redir END
现在你的寄存器a中有了一个带行号的目录了。只用了几行命令你就漂亮地完成任务了,想到这这里你的眼睛眯得更小了……
注:这里用到的函数是我们在讲折叠时说过的getline("."),表示返回当前行。line(".")则返回当前的行号。这两个函数的详细用法见文档。通过对这个脚本进行扩充我们甚至可以让它抓取含小节的目录。
上面的例子演示了通过:redir用户能对寄存器的内容进行进一步的加工而不只是简单的摘录,它增加了寄存器的使用范围。这正是与redir之所以成为寄存器重要性质之一的重要原因。在Vim7.0之前的版本中不支持重定向内容到变量,所以寄存器成了唯一选择。考虑到:redir是比较重要的命令,寄存器吃香也就不足为奇了。但在Vim7开始支持重定向内容到变量后,寄存器就没那么重要了——当然如果你希望方便地将重定向的内容插入到文件中的话寄存器仍是理想之选。关于:redir的更多内容,将会另外解说。
表达式寄存器
虽说是寄存器但从各种角度来看这都是个冒牌的寄存器。它的主要作用是实时计算表达式的值。适用的场合:在编辑输入时、在命令窗口输入时、在搜索时。使用的方式是按Ctrl-R再按等号(<C-R>=),接着输入表达式,原来输入的位置就会插入表达式的值。只要是合法的表达式都可以使用。我们知道字串可以做为合法的表达式,所以在插入模式下按Ctrl-R =然后输入"abc"(注意包括")当前位置就插入了abc。当然我们不会为了输入字串而使用这个寄存器。现在寄存器a中保存着一个数字,你想在当前文档中搜索该数字4倍的另一个数,你当然不想自己计算。这时使用表达式寄存器:/<Ctrl-R>=@a*4<Enter>/<Enter> 。其中<Ctrl-R>不是让你输入这8个字符而是按组合键Ctrl-R,同理<Enter>表示这里按了回车。任何时候当你需要插入一个表达示的值时都可以使用这个寄存器。
如果在输入=号后直接按回车没有输入表达式的话默认使用上一次使用的表达式。
在上一个例子中,如果你把刚才的目录贴在文件的开头(当然是开头),会发现行号不准了因为所有的内容都被往下移了——第一行现在变成在目录后面了。假设增加的目录有25行(不知道有几行?:se nu),现在文章的第一行(是空行)成了第26行。当然这样问题难不倒你,让表达式寄存器重新计算一下行号就行了——将原来的行号加上25。
注:下面几个控制字符的输入方式:^I, ^R, ^M, 分别表示的是Tab键,Ctrl-R,回车。它们的输入方式是按Ctrl-V(或Ctrl-Q)再输入各自所表示的键。
:1,25norm $T^I"ty$:s/[0-9]\+$/^R=@t+25^M/^M
:1,25norm 在1到25行之间(目录区)执行一般模式命令
$T^I 移到行末,将光标定位到最后一个制表符后(也就是第一个数字的位置)
"ty$ 将数字复制到寄存器t中
:s/[0-9]\+$/ 将行末的数字(每一章的行号)
^R= 插入表达式
@t+25 将寄存器t中的数字加上25
^M 插入回车结束表达式
/^M 结束s命令并在插入回车键
<Enter> 在全部输入完成后别忘了按回车执行命令
还有一个特殊的地方可以用上表达式寄存器(Vim文档没说这是一个表达式寄存器,但它的使用方式与表达式寄存器完全一样),就是:s命令。:s命令的命令格式为::s/lhs/rhs/,表示搜索lhs并替换为rhs。一个特殊用法就是当rhs的开头为`\=‘时,这rhs将被视为表达式。lhs将被替换为表达式的值。
:" 例:将当前行中的算术式'42x31'替换为算术式的结果。
:s/42x31/\=42*31/
再回到刚才的例子,中现在我们可以用一种相对优雅的方式计算更新该目录的行号:
:1,25s/[0-9]\+$/\=submatch(0)+25/
注:submatch()只在:s命令rhs的表达式中使用。submatch(0)与原来的&在rhs的作用是一样的。submatch(1)就相当于原来rhs中的\1,依此类推。
创建标记
将光标移到某一行,使用ma
命令进行标记。其中,m
是标记命令,a是所做标记的名称。
可以使用小写字母a-z或大写字母A-Z中的任意一个做为标记名称。小写字母的标记,仅用于当前缓冲区;而大写字母的标记,则可以跨越不同的缓冲区。例如,你正在编辑File1,但仍然可以使用'A
命令,移动到File2中创建的标记A。
跳转标记
创建标记后,可以使用'a
命令,移动到指定标记行的首个非空字符。这里'
是单引号。也可以使用`a
命令,移到所做标记时的光标位置。这里`
是反引号(也就是数字键1左边的那一个)。
列示标记
利用:marks
命令,可以列出所有标记。这其中也包括一些系统内置的特殊标记(Special marks):
. | 最近编辑的位置 |
0-9 | 最近使用的文件 |
∧ | 最近插入的位置 |
' | 上一次跳转前的位置 |
" | 上一次退出文件时的位置 |
[ | 上一次修改的开始处 |
] | 上一次修改的结尾处 |
删除标记
如果删除了做过标记的文本行,那么所做的标记也就不存了。我们不仅可以利用标记来快速移动,而且还可以使用标记来删除文本,例如在某一行用ma
做了标记,然后就可以使用d'a
来删掉这一行。当然,我们也可以使用y'a
命令就可以来复制这一行了。
使用:delmarks a b c
命令,可以删除某个或多个标记;而:delmarks!
命令,则会删除所有标记。
利用:help mark-motions
命令,可以查看关于标记的更多帮助信息。
m | 创建标记 |
' | 移动到标记的文本行首 |
` | 移动到标记的光标位置 |
:marks | 列示所有标记 |
:delmarks | 删除指定标记 |
:delmarks! | 删除所有标记 |