文本文件中的行分隔符

 我来答
温屿17
2022-07-08 · TA获得超过1.2万个赞
知道小有建树答主
回答量:827
采纳率:0%
帮助的人:96.3万
展开全部

这可能是关于换行符最全面的一篇文章。即使现在不是,后面也会将新的内容补充进来,让它成为最全面的一篇。

当我们用一个编辑器打开一个文本文件,在其中输入 一个 字符'a',这时候,就会有 一个 对应的字符'a'的编码(如果编码格式是ACII码,那么这里记入的编码就是“97”,写成16进制就是“0x61”)记入到该文件中。类似的输入 一个 'b',文件中便会记入一个对应的字符'b'的编码。然而,如果我们按下键盘上的‘Enter’键,现象上看,文本内容发生了换行。但是,这时候,对应的文件中究竟记入了什么内容,来标记文件发生了换行呢?
实际上,对于这个问题,不同的操作系统,沿用了不同的操作传统。如下:

注:
Mac OS 9 以及之前的系统的换行符是CR,从Mac OS X (后来改名为“OS X”)开始的换行符是LF即‘\n',和Unix统一了。

不同平台的换行符不同,会导致的各种异响不到的问题。比如:Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
如果只是将文件在编辑器中打开,供人肉眼阅读,这个问题还是挺好处理的。换一个更加智能的编辑器就好了。有的编辑器能够自动识别行分隔符,有的甚至允许用户自己指定行分隔符。这里面我遇到的对这个问题处理最好的编辑器,是JetBrains公司出的Java集成开发环境IntelliJ IDEA。

在打开文本文件的左下方,标签标识当前文件的行分隔符,鼠标点击,会弹出一个上拉列表,允许用户修改不同的行分隔符,非常方便。(类似地,文件编码的修改也在这个位置,不能更好用了。)
比人肉眼阅读麻烦的是,写程序处理文本文件的时候。一个按行处理文本文件的程序可能能够正确处理Windows上生成的文本文件,但是换成一个平台上产生的文件,可能就无法正确运行。这时候,可能就需要先识别是不是文件的分隔符导致的问题,然后,决定是不是要做必要的转换。

上面已经提到过了,更加智能的编辑器肯定是能够识别行分隔符的。但是,很多时候,我们有的只是一个终端、命令行。所以,这部分主要介绍如何通过命令来识别行分隔符。

如果能看到文件存储的二进制字节,自然可以知道文件的行分隔符是什么,图形化的智能编辑器大部分都自带这个功能。命令行下也有好多工具可以查看文本文件的16进制输出,这里以xxd命令为例介绍(如下测试,连同本文的其他测试都是在 macOS Mojave 版本号10.14.1 环境下执行的)。

上面的命令中 -g1 的参数是指一个字节为一组查看16进制编码。从命令的结果可以看出,该文件的行分隔符是0a,也就是 \n 。xxd命令输出的右边 a.b.c. ,是带表文件文本内容,其中的点就是带表不可打印字符 \n 。而在下面的执行结果中,不难看出文件b.txt的行分隔符是 \r\n 。

有的操作系统发行版中,自带的命令行中没有上面的xxd工具,通过cat命令其实也可以查看文本文件的行分隔符。如下是cat命令各个选项的解释:

可以看出 -A 选项的作用就是在文件每行结尾显示 $ ,同时显示除了LF( \n 换行符)和TAB之外的所有不可打印字符。如下是从维基百科扒下来的不可打印字符列表:

可以看出mac系统自带的命令行cat工具不支持 -A 选项。不过,在支持的系统上,配合head命令,可以看出如果文件的换行符是 \n 输出行的末尾只会有一个 $ ,如果换行符是 \r\n ,输出行的末尾就会是 ^M$ 。从上面cat命令的解释也不难看出这一点。

如果确定了是行分隔符的导致的问题,有时候,就需要进行行分隔符的转换。最简单的方式,可能是上面提到的像IDEA那样的更加智能的图形化文本编辑器,在界面上点点点操作几下就完成了。然而,这不见得是最方便的,比如在命令行的环境中,除了命令一无所有。因此,这里着重介绍命令行下的解决方案。

提到命令行下的文件编辑sed命令肯定是绕不过去的。如果要将行分隔符从 \n 换成 \r\n 最直觉的写法可能是( -i 选项的意思是直接在原文件上进行编辑):

然而这个方法,却屡试屡败。原因就在于sed命令是按照行来读文件的,逐行处理,默认地sed认为行分隔符是 \n ,所以,不会出现在sed处理的文本行内容中,导致这个方案失败。所以,可能的解决办法就是将所有文件内容读进来处理,而不是逐行处理。解决的办法大概有如下几个:

既然sed处理的文本行中不包含换行符,我们可以用 $ 来辅助实现替换:

但是,在我的系统上,这样写的效果却是:

这里之所以 -i 选项后面加 '' 是因为这个系统上sed要求 -i 时,必须指定扩展。然而,仍然运行失败的原因在于macos没法像Linux那样将 \r 识别为特殊字符。为了给sed传入 \r 需要写成:

这里 $'' 的作用就是让其中的转义字符正确被翻译。同样的,用 $() 也可以达到这个效果,不过外面的单引号要换成双引号。

对于GNU版本的sed,可以使用 -z 选项。

下面是一个例子:

对于GNU版本的sed,也可以写一个循环,将文件全部读入之后,再交给sed处理:

到这里,换行符的识别、转换等都介绍完了。这里讲最后一个之前令我困扰的问题, ^$\r\n 这几个符号在正则匹配中的先后顺序是什么。这里,直接贴下正则表达式网站上的介绍:

也就是说,Delphi、Java和JGsoft风格的正则将CRLF看成一个整体, ^ 匹配CRLF后面, $ 匹配CRLF前面,两者都不匹配CRLF中间。而JavaScript和XPath认为CRLF是两个换行符, ^ 匹配CRLF中间和后面, $ 匹配CRLF中间和前面。

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式