Vim文本编码之坑

#20220503更新#

今天又遇到一个问题,即常见的“cat显示正常,vi显示异常”的问题。

有这样一个文件,它的编码是UTF-16(DOS),在windows下用UltraEdit打开能正常显示,提示编码是UTF-16(DOS)。

但是在服务器(centos7系统)用vi打开便是一串乱码了,但说乱也不是很乱,因为夹杂着正常字符的,能隐约看到部分内容,提示内容是这样:

 

解决方法:根据UltraEdit的提示,知道编码的格式为UTF16le,使用utf16le格式打开文件: vim xx.txt -c "e ++enc=utf16le" 

于是把vimrc文件的set fenc(set fileencodings)改了一下,将utf-16的优先级调到前面,文件能正常显示了。

相关vimrc设置:

set encoding=utf-8
set fileencodings=ucs-bom,utf-8,utf-16le,default,latin1,gb2312,cp936,gbk,gb18030

 

注:其中ucs-bom用于检查文件开头部分的Unicode BOM(Byte Order Mark, 字节序标志),它应当放在"utf-8"或者其他Unicode编码之前,从而可以正常的工作。latin1(ISO-8859-1)为单字节编码。保险起见,修改vimrc文件最好先备份,以防出现乱码错误。

注,据本人经验,utf16-le和utf8的格式类似,vi打开文件时,一般会分不清他们,vi通常会将他们之间优先级较高的作为打开的编码格式。鉴于文本文件的出现UTF-8编码格式的概率要大于utf-16le,为保证大多数情况下的成功率,还是将utf-8的优先级放在utf-16le之前。而对于utf16le,则建议打开的时候显式的指定文件格式打开 vi coding_test.txt -c "e ++enc=utf16le" 

 

#10月10日更新#

今天在windows下用visual studio打开多个fortran文件,均出现了之前提到的“Some  bytes have been replaced with...”错误,这就比较尴尬了。最终发现,是因为将windows系统的默认编码设置成了UTF-8的原因。最后改回原来的默认设置,把那个“支持UTF-8编码(beta)”选项关闭之后,就没有出现乱码了。

#10月9日更新#

今天在Linux 上用vim 打开一个文件,vim将其识别成gb18030编码,能正常显示中文,然后进行了修改,保存。之后在windows上用visual studio  打开,提示了之前提到的“Some  bytes have been replaced with...”错误,中文无法解决。

解铃还须系铃人,最后是在vim中打开这个文件,set fileencoding=utf-8,将文件的编码格式设置成UTF-8,然后保存。之后再在windows上用visual studio打开,就正常了!

-----------------------------------------------------------------------------------------------------------------------------------------

工作原因,需要在windows和linux上同时对代码进行编辑。有时候会出现一个诡异的现象,在linux的vim显示正常的文件,在windows系统中用visual studio打开时提示

File Load  

Some bytes have been replaced with the Unicode substitution character while loading file xxx.f90 with Chinese Simplified (GB2312) encoding. Saving the file will not preserve the original file contents.

打开的文件出现的是一堆乱码。 这究竟是怎么造成的?

从字面上看,是这个文件原本是用GB2312进行编码的,但是文件中的一部分是用Unicode编码的。

问题就在于windows和Linux 下的vim之间的默认的文本编码的差异。

在Windows里,默认保存的文本文件,中文的编码格式是GBK编码(cp936)。

而在Linux系统中,当用vim打开windows保存的文本文件时,会先尝试用默认的编码格式(UTF-8)去转换,如果出现转换错误,再尝试用vim配置文件中列出的其它编码格式读取。

这个vim配置文件是vimrc,一般位于/usr/share/vim/vimrc。在这个配置文件中,通过设置fileencodings的值,来告诉vim编辑器依次尝试用这些编码格式打开文件。

 

设想出现如下的情况:在windows下创建一个文本文件,以windows默认格式(cp936)保存。但是,在linux系统中用vi打开这个文件时,由于某种原因,vi错误地将其识别成了UTF-8编码。这时候再对文件进行改动,那么改动部分就会以UTF-8的编码格式写入。之后再在windows下打开这个文件,就会出现乱码的错误。

 

另外,如果用vim打开文件时提示:"xxxx.txt" [第 xx 行无效字符][dos] xxxxL, xxxxC  ,则意味着出现了转换错误。

造成转换错误意味着文件的文本编码不正确。这里的“文本编码不正确”并不一定意味着所有的编码不正确,因为可能出现一个文件用两种编码保存的情况(可能在文件的这一行用的UTF-8对文本进行编码,在这个文件的下一行用GBK编码文本)。可能用vim打开文件时候,一部分文本能正常显示——这部分文本的编码和vim当前的编码一致,但另一部分文本不能正常显示,这时候尝试切换使用不同格式的编码打开文件,有可能使得这部分文本正常显示(原来能正常显示的文本可能因为切换了编码不能正常显示)。

比如以gbk编码打开文件 vi coding_test.f90 -c "e ++enc=gbk"

在vi中查看文件的编码 set fileencoding

 

关于中文编码

常见的中文编码有GB2312, GBK, GB13030等。这些带GB*前缀的,是中国定的。其中GB2312历史最早,1980年,支持的汉字字符也最少;GBK 1.0版本是1995年推出的;到了2000年GB18030推出,这一版本除了汉字外,还加入藏、蒙、维等字体

而国际上采用的是UTF编码也支持中文,但是windows下还是默认用的GBK编码。

 

参考

常见字符编码扫盲(UTF,Unicode, GB2312) - 四-儿 - 博客园 https://www.cnblogs.com/sier/archive/2011/10/02/5676457.html

在Vim中查看文件编码 - 浮沉一梦 - 博客园 https://www.cnblogs.com/jjzd/p/7380487.html

Vim 编辑器底端 [noeol], [dos] 的含义_王佳伟的博客-CSDN博客 https://blog.csdn.net/strongwangjiawei/article/details/8236703

不同平台文件格式:dos、unix、mac | 程序员技术之旅 https://www.zhangbj.com/p/370.html

 

----------------------------20220428----------------------------------

附录 关于Vim的一些选项设置

fileencoding选项('fileencoding' 'fenc')

默认值: 空

设置缓冲区文件中的字符编码。

当'fileencoding'与'encoding'不同时,将在写文件时候完成转换。

当'fileencoding'是空时,将会使用'encoding‘的值,此时在读写文件时候不会发生转换。

当'encoding'和'fileencoding’均为unicode编码,且'fileencoding'不是utf-8时,转换同样会发生。这是因为Unicode内部通常是作为utf-8存储的。

警告:转换可能会导致信息的丢失!当'encoding'是'utf-8'或者其他Unicode编码时,转换最有可能以反向转换生成相同文本的方式发生。当'encoding'不是'utf-8'时,会丢失一些字节!

参见'encoding'查看可能的值。此外,还可以指定转换器可以处理的值,参见bypte-conversion。

当读取文件’fileencoding'将会从'fileencodings'中设置。为了读取一个对于'fileencoding'设定不起作用的特定编码的文件,需要使用++enc参数。一个例外:当'fileencodings'为空时,使用’fileencoding'的值。对于一个新的文件,使用'fileencoding‘作为全局值。

在这里,加入“8bit-”和“2byte-”前缀没有意义,它们被忽略了。当设置了这个选项,值将会转换成小写,所以你也可以用大写字母的值设置。 '_'字符串用'-‘替换。如果从'encoding'列表中识别出一个名称,它将被标准名称替换。例如,“ISO08859”变为“iso-8859-2”。

当设置了这个选项,在开始编辑文件之后'modified'选项将被被设置,因为当写文件时文件将会改变。

记住从模式行改变'fenc‘将会在文本被读取之后发生,所以当文件被写入时候会应用这些选项。如果你在模式行设置了’fenc',你需要设置‘nomodified'以避免无法使用“:q”的情况。

当'modifiable‘关闭时,这个选项不能被改变。

'fe' 注意:在6.0版本之前,这个选项指定了整个Vim的编码,这是个错误。现在使用'encoding'代替了。以前的简称是'fe’将不再被使用。

 

fileencodings选项('fileencodings' 'fencs')

默认值:“ucs-bom";当'encoding'设置为Unicode编码时,默认是”ucs-bom,utf-8,default,latin1“)

{仅当使用 +multi_byte特性编译时候可用}{不是在Vi中}

这是在对一个已有文件进行编辑时,考虑的一个字符串编码列表。当读取一个文件时,Vim先尝试列表中的第一个字符串编码。如果检测到错误,就尝试接下来一个。当检测到编码起作用,将会把这个值设置到'fileencoding‘变量中。如果全部失败'fileencoding'将会设置为空值,这将意味着将会使用'encoding'的值

警告:转换将会导致信息的丢失!当'encoding'是"utf-8"(或者一个其他的Unicode编码)时,转换最有可能以反向转换生成相同文本的方式发生。当'encoding'不是"utf-8"时,会丢失一些非-ASCII字符!可以使用++bad参数去指定如何处理这些不能被转换的参数。

++bad 这个参数指定了不能被转换的字符以及非法字符事后的处理方式。可以有以下三种值:

++bad=X 对于每个坏字符用一个单字节的字符替换

++bad=keep 保持原来的坏字符,不要转换。注意这将会导致在你的文本中出现非法字节!

++bad=drop 移除坏字符。

默认的比如"++bad=?“: 用每个坏字符用问号字符串替换。在一些情况下一个倒问号将会被使用(0xBF)。

注意不是所有的命令都会用到++bad 参数,即使在对这些命令添加了++bad选项了,它们也不会返回一个错误。比如:write。 、

注意,当读取时候,'fileformat‘和'fileencoding’选项将会设置使用到的格式。当没有进行写操作时,下一次的写操作将会使用旧选项。对于'binary'选项也是一样。

 对于一个空文件或者一个仅有ASCII字符串的文件,大多数的编码都会起作用,所以将会使用‘fileencodings’列表的(除了"ucs-bom"以外)第一个条目。如果你需要其他的编码,使用BufReadPost 自动指令事件来测试你预期的编码是否被使用。比如:

au BufReadPost *if search('\S', 'w') ==0) |

   \ set fenc=iso-2022-jp |end if

如果文件没有包含非空字符串,将会把设置'fileencodings'成"iso-2022-jp"。

当使用了++enc参数,‘fileencodings'的值将不会被使用。

注意'fileencodings'不对一个新文件起作用,这时候将会使用'fileencoding'选项。

 可以使用以下命令来设置:

:set global fenc=iso-8859-2

这意味着不存在的文件将会得到与空文件不同的编码。

特殊的值”default“可以被用于从环境中编码(这是'encoding‘的默认值)。当'encoding'设置成"utf-8",且你的环境使用的是非latin1编码(比如俄语)时,这非常有用。

当'encoding‘是”utf-8"且文件包含了一个非法的字节序列时,他不被被识别为UTF-8。你可以使用8g8命令去查找非法字节序列。

错误值:                            

错误的原因:

latin1, utf-8

utf-8,ucs-bom,latin1 

cp1250,latin1

"latin1"将会总是使用

在utf-8文件中BOM不会被识别

"cp1250"将会被使用

如果'fileencodings'是空的,'fileencoding'将不会被更改。

对于可能的值,请参见'fileencoding'。

直到下一次文件被读取之前,至二个选项将不会起作用

 

'fileformat' 'ffs'选项('fileformat' 'ffs'

'fileformat' 'ff' 字符串(MS-DOS, MS-Windows, OS/2 默认的值: "dos",Unix默认值:"unix",Macintosh默认值:"mac")

缓存 {不是在vi中}

这个将会设置当前缓存中的<EOL>,用于从文件中读/写缓存:

dos <CR> <NL>

unix <NL>

mac <CR>

当"dos"被使用,在文件最后的CTRL-Z将会被忽略。参见file-formats和file-read。

对于文件的字符编码,参见'fileencoding'.

当设置了'binary',将忽略'fileformat'的值,文件I/O与设置为"unix"的工作方式类似。当开始编辑一个文件时,'fileformats'不为空且'binary’关闭,这个选项将会自动设置。

当这个选项设置时,在编辑文件之后,'modified‘选项将被设置,因为在写文件时文件将会不同,这个选项不会被改变当’modifiable'关闭时。

为了向前兼容:当这个选项设置为'dos'时,'textmode‘被设置,否则'textmode'将被重置。

 

'fileformats' 'ffs'选项('fileformats' 'ffs')

'默认值:

Vim+Vi     MS-DOS, MS-Windows OS2: "dos, unix",

Vim          Unix: "unix,dos",

Vim          Mac: "mac, unix, dos",

Vi             Cygwin: "unix,dos",

Vi             others:""

global 

{not in vi}

这给出当开始编辑一个新的缓存和从文件中读取到指定缓存时,行结束符(<EOL>)的格式:

- 当为空时,将用'fileformat'定义的格式。这不是自动设置的。

- 当设置了一个名字,再回在新的缓存被打开时应用格式。'fileformat'将会根据缓存设置。当文件被读进一个已有的缓存中时,不管对于这个缓存'fileformat'设置成什么,都将使用'fileformats'的名称。

- 当超过一个名字存在时,将会在读取文件是进行自动<EOL>检测。当开始编辑文件时,关于<EOL>的检测已经完成;

1. 如果所有的行都以<CR><NL>结尾,且'fileformats'包含了"dos",'fileformat'将设置成"dos"。

2. 如果<NL>被发现,且'fileformats'包含了"unix",'fileformat'将设置成"unix"。注意当一个<NL>被发现前面没有<CR>时,"unix"的优先级在"dos"之前。

3. 如果'fileformat'没有被设置,且如果'fileformats'包括了"mac",'fileformat'将被设置为"mac"。

这意味着"mac"仅在以下情况下被采用:

"unix"不存在或在文件中没有发现<NL>,且"dos"不存在或在文件中没有<CR><NL>。

例外:如果"unix"被选定,但在<NL>之前有<CR>,且在文件的头几行中,<CR>符号的数目比<NL>符号的多,则使用"mac"

4. 如果'fileformat'仍然未设置,将使用'fileformats'中的第一个值。

当从文件中读取到存在的缓存中时,以同样的方式完成,但这种情况就像"fileformat"仅为该文件设置了适当的格式一样,选项没有更改。

当设置了'binary'时,‘fileformats'的值将不会采用。

注意到当Vim开始以空的缓存开始时,这个选项将不会被使用。而是在你的.vimrc文件中设置的'fileformat'

对于具有类似DOS的<EOL>(<CR><NL>)的系统,当读取被":source"的文件和对于vimrc文件时,将会以以下方式进行<EOL>检测:

- 当'fileformats'为空时,没有自动检测。将会使用Dos格式。

- 当'fileformats'设置为一个以上名字是,自动检测将会进行。这是基于文件中第一个<EOL>:如果在它之前有<CR>,将使用Dos格式,否则将使用Unix格式。

同样参见file-formats。

对于向前兼容:当这个选项设置为空字符或者单个格式(没有逗号)时,'textauto'将被重置,否则将会设置'textauto'。

注意:当'compatible'被设置时,这个选项被设置为Vi的默认值,当'compatible‘被重置时,这个选项将会设置成Vim的默认值。

posted @ 2020-10-07 23:06  chinagod  阅读(1416)  评论(0编辑  收藏  举报