foo
bar
我视觉上将其选中并复制。
文本现在存储在未命名的寄存器
"
中,这是其文本内容(:reg "
的输出):"" foo^Jbar^J
根据此图表,看来
^J
是换行符的插入符号。 如果要通过键入以下内容来复制
a
寄存器中的未命名寄存器::let @a = @"
这里是其内容(
:reg a
的输出):"a foo^Jbar^J
它没有变化。
如果现在我通过输入
:let @/ = @"
在搜索寄存器中复制它,则其内容(:reg /
的输出): "/ foo^@bar^@
根据上一张图表,
^@
似乎是空字符的插入符号。 a
寄存器)?如果我在命令行上(或在
/
之后的搜索内)插入未命名的寄存器,则键入:<C-R>"
,将插入以下内容::foo^Mbar^M
同样,根据最后一张图表,
^M
似乎是回车符的插入符号。为什么换行符在命令行上自动转换为回车符?
/>
编辑:
通常,您可以通过键入以下内容来插入文字控制字符:
<C-V><C-{character in caret notation}>
例如,您可以通过键入
<C-R>
来插入文字<C-V><C-R>
。似乎是任何控制字符。但是我注意到我无法在缓冲区内或命令行中插入文字LF,因为如果我键入:
<C-V><C-J>
它将插入^@
(一个空字符)而不是^J
是否出于同样的原因将LF转换为搜索寄存器中的NUL?
编辑2:
在
:h key-notation
中,我们可以阅读以下内容:<Nul> zero CTRL-@ 0 (stored as 10) <Nul>
<NL> linefeed CTRL-J 10 (used for <Nul>)
第一行的
stored as 10
部分和第二行的used for <Nul>
部分可能表明LF和NUL之间存在某种重叠,并且可以将它们解释为同一件事。但是它们不可能是同一回事,因为在执行上一条命令:let @/ = @"
之后,如果我以正常模式键入n
来到达下一行出现的两行foo
和bar
,而不是得到一个正匹配项,则得到以下内容错误消息:E486: Pattern not found: foo^@bar^@
除了此链接外,它还解释了NUL表示字符串的结尾,而LF表示文本文件中行的结尾。
如果NUL是
stored as 10
(如帮助信息所示),与LF的代码相同,那么Vim如何使两者之间有区别?编辑3:
就像帮助说的那样,也许LF和NUL用相同的十进制代码
10
编码。由于上下文,Vim使这两者之间有所不同。如果它在缓冲区或任何寄存器中(除了搜索和命令寄存器之外)遇到十进制代码为10
的字符,则将其解释为LF。但在搜索寄存器(
:reg /
)中,它将其解释为NUL,因为在搜索的上下文中,Vim只搜索end of line in a file
的概念没有意义的字符串,因为字符串不是文件(这很奇怪,因为您仍然可以在搜索模式中使用原子\n
,但这也许是仅是正则表达式引擎的功能?)。因此它自动将10
解释为NUL,因为它是最接近的概念(end of string
≈end of line
)。同样,在命令行/命令寄存器(
:reg :
)上,它将代码10
解释为CR,因为end of line in a file
的概念在这里没有意义。最接近的概念是end of command
,因此Vim将10
解释为CR,因为按Enter
是结束/执行命令的方式,而CR与按Enter
相同,因为在用<C-V><Enter>
插入文字时,将显示^M
。 br /> 也许代码为
10
的字符的解释会根据上下文而改变:搜索字符串(^J
)命令行末尾(
^@
)#1 楼
首先,感谢您的这篇非常全面和周到的文章。经过一些测试,我得出了以下结论:
使用插入符号显示控制字符表示法:
^M
(回车)为<CR>
,^J
(换行)为<LF>
。在缓冲区中,<EOL>
(行尾)显示为新的屏幕行,并使用Enter键输入。 <EOL>
取决于缓冲区的文件格式:<EOL> = <CR>|<LF>|<CR><LF>
分别对应mac|unix|dos
。编辑缓冲区时,始终设置文件格式。要更改打开的缓冲区的文件格式,可以使用以下命令将
<EOL>
转换::set f[ile]f[ormat]=mac|unix|dos
除了转换
<EOL>
之外,该命令还将<LF>
转换为<CR>
将文件格式从mac
更改为unix|dos
时,将文件格式从<CR>
更改为<LF>
,相反,将文件格式从unix|dos
更改为mac
。要查看缓冲区的实际字节,可以使用以下命令,使用方便的十六进制编辑器xxd将缓冲区的文本表示形式转换为十六进制表示形式::%!xxd
在寄存器(用命令
:reg[isters]
或:di[splay]
显示)中,无论缓冲区的文件格式如何,<EOL>
始终显示为^J
(但并非所有^J
都是<EOL>
)。但是,<EOL>
会按原样存储。为了能够将视觉上真实的^J
(即<LF>
)与寄存器中的其他^J
(即<EOL>
)区分开来,可以使用以下命令显示十六进制值,而不是不同于<EOL>
的控制字符的插入记号: /> :set d[ispla]y=uhex
在搜索模式和替换字符串中: br />
\r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
\n = <EOL>
这表明当文件格式为
dos
时,由于<LF>
和<EOL> = <CR><LF>
不能输入<C-V><C-M>|<C-V><EOL> = <CR>
。替换字符串中:与
<EOL>
不同的换行被解释为<EOL>
; <EOL>
被解释为<NUL>
。因此,根据4,
:%s[ubstitute]/\r/\r/g
用<EOL>
替换了缓冲区中与<EOL>
不同的所有换行符,而:%s[ubstitute]/\n/\n/g
替换缓冲区中每个带有<EOL>
的<NUL>
。在搜索寄存器
/
和命令寄存器:
中,<EOL>
转换为与<EOL>
不同的换行符当分别从带有/<C-R>{register}
或:<C-R>{register}
的寄存器插入时; <NUL>
;分别从带有:let @/=@{register}
或:let @:=@{register}
的寄存器插入时。当使用
<EOL>
从寄存器插入时。为什么将换行符转换为搜索
寄存器内的Null字符并在命令行上转换为回车符?寄存器,您需要输入
<EOL>
并将其放入寄存器i<C-R>{register}
中。如果文件格式为<LF>
,则可以通过在空行上使用"
来实现;如果文件格式为<LF>
,则可以使用"
来实现;如果文件格式为unix
,则无法输入yy
(请参阅第5页)。现在您的语句部分错误,因为
您不会使用相同的方法将
mac
从寄存器i<C-V><C-M><Esc>yl
复制到搜索寄存器dos
和命令寄存器<LF>
中。您可以使用<LF>
复制到寄存器"
和/
复制到寄存器:
。在这两种情况下,分别使用:let @/=@"
和/
会得到相同的结果(:<C-R>"
); 用两种不同的复制方法进行的
:
转换仅在文件格式为/<C-R>"
时发生。如果是:<C-R>"
,则将<CR>
复制到寄存器<LF>
或寄存器unix
时不会转换,如果是mac
,则您甚至无法输入<LF>
。不知道其背后的原因。评论
为什么这是如此难以理解...我通过SO,vim-SE和vim帮助方面的几篇文章进行了研究,但并不完全一致,仍然感到困惑。
–硫蛋白
17年1月1日在7:57
评论
有时,意外的NULL字符的出现是由处理字符串的基础C函数引起的。有关C如何处理链接到的字符串的解释说明了C在内部用NULL分隔字符串。 NULL在文本中很少出现,因此使其成为良好的字符。这样的结果是,如果C程序(vim)试图将“空”字符串传递到内部C函数中,则为例如someFunction(arg1,“”),其中arg 2是“”,即“引号之间的项目,实际上什么都不是-”空“。可能会出现NULL,因为它由定界的底层C实现“添加”字符串。我不知道您将如何检查该字符串-但我想到它是可能的原因。
另请参见:substitute中有关\ r和\ n差异的讨论。