ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Vim 中用换行符替换字符

我正在尝试用新行替换当前文件中的每个 ,

:%s/,/\n/g 

但它会插入看起来像 ^@ 的东西,而不是实际的换行符。该文件未处于 DOS 模式或任何状态。

我应该怎么办?

如果您像我一样好奇,也请检查问题Why is \r a newline for Vim?

Stack Overflow 是一个编程和开发问题的网站。这个问题似乎离题了,因为它与编程或开发无关。请参阅帮助中心的 What topics can I ask about here。也许 Super UserUnix & Linux Stack Exchange 会是一个更好的提问位置。
@jww 这个问题已有 10 年历史了......似乎太老了,无法迁移。有很多这样的问题,例如:stackoverflow.com/questions/10175812/…
@jww vim 是程序员常用的工具,关于程序员常用工具的问题在 Stack Overflow 中讨论。虽然显然这更适合 Vi and Vim

K
Konrad Rudolph

使用 \r 而不是 \n。

替换为 \n 会在文本中插入一个空字符。要获得换行符,请使用 \r。但是,当搜索 换行时,您仍会使用 \n。这种不对称是由于 \n\r do slightly different things

\n 匹配行尾(换行符),而 \r 匹配回车符。另一方面,在替换中,\n 插入一个空字符,而 \r 插入一个换行符(更准确地说,它被视为输入 CR)。这是一个使用 Vim 命令行功能的小型非交互式示例来说明这一点(换句话说,您可以将以下内容复制并粘贴到终端中以运行它)。 xxd 显示生成文件的十六进制转储。

echo bar > test
(echo 'Before:'; xxd test) > output.txt
vim test '+s/b/\n/' '+s/a/\r/' +wq
(echo 'After:'; xxd test) >> output.txt
more output.txt
Before:
0000000: 6261 720a                                bar.
After:
0000000: 000a 720a                                ..r.

换句话说,\n 已将字节 0x00 插入到文本中; \r 已插入字节 0x0a。


/r 被视为按下 Enter/Return 键。它适用于所有平台。
我希望这适用于经典 vi。在 AIX v6.1 上,\r 不能这样工作。但是您可以按 Ctrl-V Enter 代替输入 \r,它可以工作。
我参加晚会迟到了。如果 \r 插入 <CR>\n 插入 null,我将如何用回车替换某些内容?
@SunnyRaj 你确定 CR 和 LF 的历史吗?我的印象是,最初 LF 将纸张向前移动一排但不移动打印头,而 CR 移动打印头但不移动纸张。因此,如果您的操作系统在打印之前没有转换输入,您就不能只使用 LF 或 CR 来获得正确的输出。 MS DOS 使用原始打印机数据作为文本文件格式,Mac OS 使用 CR 并将其转换为打印机的原始格式,UNIX 使用 LF 并将其转换为打印机的原始格式。
C
Community

这是诀窍:

首先,将您的 Vi(m) 会话设置为允许使用特殊字符进行模式匹配(即:换行符)。将这一行放在你的 .vimrc 或 .exrc 文件中可能是值得的:

:set magic

接下来,执行:

:s/,/,^M/g

要获取 ^M 字符,请键入 Ctrl + V 并按 Enter。在 Windows 下,执行 Ctrl + QEnter。我能记住这些的唯一方法是记住它们的意义有多大:

A: 用来表示换行符的最差控制字符是什么? B:要么是 q(因为它通常表示“退出”)要么是 v,因为很容易误按 Ctrl + C 并杀死编辑器。答:就这样吧。


我在 Windows 上使用 GVim,我既不需要 :set magic(它也不在我的 ~/_vimrc 中)也不需要 ctrl-q。只需一个简单的 ctrl-v 然后回车就可以为我创建 ^M 字符。
Cv 不代表换行符;这是“转义下一个文字字符”命令。我不知道 Cv 是什么的助记符,但它在心理上没有映射到换行符是有原因的。
Ctrl-v 是“逐字”的助记符 - 即将按下的下一个键转义到其“逐字”键码/字符。在 Windows 中,它是粘贴:让事情变得熟悉。 Ctrl-Q 可能是“(un)Quote”。无论如何,这很愚蠢-但您可以在二进制文件中使用它-例如通过Ctrl-Z搜索Ctrl-A(我猜是Ascii 1-26)。
Ctrl-C 实际上并没有杀死编辑器,尽管它可以取消您回到正常模式。 Ctrl-V 表示逐字,Ctrl-Q 表示有人错误地加载了 $VIMRUNTIME/mswin.vim 配置文件。你不需要mswin。只需使用您自己的 vimrc 即可。
哇——这太棒了。我以前做sed -n l 到现在。很高兴知道在 vim 中使用 Ctrl-v 也可以达到同样的效果。
s
sjas

在语法 s/foo/bar 中,\r\n 具有不同的含义,具体取决于上下文。

短的:

对于 foo

\r == “回车” (CR / ^M)
\n == 在 Linux/Mac 上匹配“换行” (LF),在 Windows 上匹配 CRLF

对于 bar

\r == 在 Linux/Mac 上生成 LF,在 Windows 上生成 CRLF
\n == "null byte" (NUL / ^@)

在 linux 中(即在网络服务器上)编辑最初在 windows 环境中创建并上传(即 FTP/SFTP)的文件时 - 您在 vim 中看到的所有 ^M 都是 linux 所做的 CR不翻译,因为它仅使用 LF 来描述换行符。

更长(带有 ASCII 数字):

NUL == 0x00 == 0 == Ctrl + @ == ^@ 显示在 vim
LF == 0x0A == 10 == Ctrl + J
CR == 0x0D == 13 == Ctrl + M == ^M 在 vim 中显示

这是 ASCII control characters 的列表。通过 Ctrl + V,Ctrl + ---key--- 将它们插入 Vim。

在 Bash 或其他 Unix/Linux shell 中,只需键入 Ctrl + ---key---。

在 Bash 中尝试 Ctrl + M。这与按 Enter 键相同,因为 shell 会意识到这意味着什么,即使 Linux 系统使用换行符来分隔行。

要在 bash 中插入文字,在它们前面加上 Ctrl + V 也可以。

在 Bash 中尝试:

echo ^[[33;1mcolored.^[[0mnot colored.

这使用 ANSI escape sequences。通过 Ctrl + VEsc 插入两个 ^[

您也可以尝试 Ctrl + V,Ctrl + M, Enter,这将为您提供:

bash: $'\r': command not found

还记得上面的 \r 吗? :>

这个 ASCII control characters 列表与完整的 ASCII symbol table 不同,因为可以在此处找到通过 Ctrl 键(哈哈)插入控制台/伪终端/Vim 的控制字符。

而在 C 和大多数其他语言中,您通常使用八进制代码来表示这些“字符”。

如果您真的想知道这一切的来源:The TTY demystified。这是您将遇到的有关此主题的最佳链接,但请注意:有龙。

TL;博士

通常 foo = \nbar = \r


所以我很好奇你如何用回车替换一个字符
@codeshot :s/x/^M/g 应该可以。通过 ctrl-vctrl-m 插入 ^M
谢谢sjas,你知道这个问题是有史以来最奇怪的问题之一。 1008 票投给了答案,它基本上只是说“vim 做了你发现的事情。那是因为 vim 做了你发现的事情。永远不要忘记 vim 做了你发现的事情。”我希望找到模式中有趣字符的代码候选清单,替换和奇怪的原因,以便它容易记住和预测其他类似的奇怪。那会得到我的投票。
@codeshot ascii 控制字符列表可能会对您有所帮助。如需进一步参考,请参阅 cs.tut.fi/~jkorpela/chars/c0.html。我将更新我的答案以包含两个链接。
P
Peter Mortensen

你需要使用:

:%s/,/^M/g

要获取 ^M 字符,请按 Ctrl + v,然后按 Enter


我必须执行 才能获得 ^M 字符。
A
Arslan Ali

\r 可以为您完成这里的工作。


P
Peter Mortensen

在 Windows 上使用 Vim,使用 Ctrl + Q 代替 Ctrl + V。


P
Peter Mortensen

这是我认为的最佳答案,但在表格中会更好:

Why is \r a newline for Vim?

所以,改写:

您需要使用 \r 在正则表达式替换中使用换行符(ASCII 0x0A,Unix 换行符),但这是替换所特有的 - 您通常应该继续使用 \n 作为换行符和\r 用于回车。

这是因为 Vim 在替换中使用 \n 来表示 NIL 字符(ASCII 0x00)。您可能希望 NIL 改为 \0,释放 \n 以使其通常用于换行,但 \0 在正则表达式替换中已经有意义,因此它被转移到 \n。因此,进一步将换行符从 \n 移动到 \r(在正则表达式模式中是回车符,ASCII 0x0D)。

Character                | ASCII code | C representation | Regex match | Regex replacement
-------------------------+------------+------------------+-------------+------------------------
nil                      | 0x00       | \0               | \0          | \n
line feed (Unix newline) | 0x0a       | \n               | \n          | \r
carriage return          | 0x0d       | \r               | \r          | <unknown>

注意:^MCtrl + V Ctrl + M 在 Linux 上)在用于正则表达式替换而不是其他人建议的回车(我刚刚尝试过)。

另请注意,Vim 将根据其文件格式设置保存到文件时转换换行符,这可能会造成混淆。


P
Peter Mortensen

Eclipse 开始,^M 字符可以嵌入一行,并且您希望将它们转换为换行符。

:s/\r/\r/g

P
Peter Mortensen

但是,如果必须替换,则以下内容有效:

:%s/\n/\r\|\-\r/g

在上面,每一下一行都被下一行替换,然后是 |- 并再次换行。这用于 wiki 表格。

如果文字如下:

line1
line2
line3

它改为

line1
|-
line2
|-
line3

P
Peter Mortensen

这是对我有用的答案。来自这个人:

----引用 Use the vi editor to insert a newline char in replace

其他一些我必须做的事情,我不记得了,然后不得不抬头看。

在 vi 中,要在搜索和替换中插入换行符,请执行以下操作:

:%s/look_for/replace_with^M/g

上面的命令会将所有“look_for”实例替换为“replace_with\n”(\n 表示换行符)。

要获得“^M”,请输入组合键 Ctrl + V,然后(释放所有键)按 Enter 键。


P
Peter Mortensen

如果您需要对整个文件执行此操作,我还建议您可以从命令行尝试:

sed 's/\\n/\n/g' file > newfile

请注意,这需要 GNU sed。尝试 printf 'foo\\nbar\n' | sed 's/\\n/\n/g' 看看它是否可以在您的系统上运行。 (感谢 freenode 上#bash 的好人提出这个建议。)
是的,但问题是关于 Vim。有 Stack Overflow 问题 How can I replace a newline (\n) using sed?