现在回车键一般指键盘上的 Enter 键,当打字时敲下回车键,文本会跳到下一行。当保存文件时会有一个或两个不可见字符保存到文件中。这两个字符分别是回车符 CR (Carriage Return) 和换行符 LF (Line Feed),Carriage Return 是指滑块回到一行的最左侧,Line Feed 原指喂纸的意思,将纸张向前推,达到的效果就是换行。
在计算机编码上,分别用 'r' 和 'n' 代表 CR 和 LF 字符。‘r' 字符在终端编程中用来制作进度条。因为 'r' 在终端表现上会让光标回到行首,从而可以覆盖之前的输出,达到字符在原地更新的效果。
#!python3
import
sys
import
time
def
do_something
()
:
pass
def
bar_update
(rate)
:
print(
"当前进度: {:3d}%"
.format(rate),
"▋"
* (rate //
2
), end=
"r"
)
sys.stdout.flush()
time.sleep(
0.05
)
if
__name__ ==
'__main__'
:
n =
0
while
True
:
do_something()
bar_update(n)
n +=
1
if
n ==
100
:
n =
0
print(
'r'
+
' '
*
65
, end=
'r'
)
换行符 ‘n' 在终端上表现就是换行,一般日志打印中我们不会输出 'rn',如果需要换行只用在字符串后面加上 'n' 即可。
早期的 Windows 在保存文本文件时会使用 'rn' 来作为一行的结尾,而 linux 会使用 'n' 作为一行的结尾,MacOS 则选用了 'r' 作为一行的结尾。这导致了文本文件在不同系统上打开时会出现兼容性问题,要么多行变成一行,要么每一行会多出一个乱码。这就是著名的 CR LF 之争,现代编辑器基本上都支持这三种行分隔方案:
notepad2
vscode
文本文件常见的两类问题,一类是编码问题,另一类就是换行问题。它们都可能导致不同的编辑器打开出现乱码,或程序读取文件时发生错误。
如何判断文件的换行方式是 CRLF 还是 LF,或者是 CR
这个问题实际操作起来还是比较麻烦的,因为打开文件读取一行判断行的结尾这个操作可能会受编码格式的影响。用 python 的 readline() 函数无法正确读取到 'rn',有可能 'r' 字符会被 readline() 处理掉。并且有些编码比如 utf16 可能并不是以 'rn' 作为行的分隔,它可能会用 'rx00n' 作为行的分隔。
使用 Python 判断一个文件的换行模式,有效的方式可能就是以二进制方式解析文件,一旦文件经过解码打开,换行可能会发生变化。
判断换行模式的函数如下:
def
check_crlf_ending
(file_path)
:
with
open(file_path,
'rb'
)
as
file:
line = file.read(
1000
)
# print(repr(line))
if
b'rn'
in
line
or
b'rx00n'
in
line:
return
'CRLF'
if
b'r'
in
line:
return
'CR'
return
'LF'
通过二进制模式读取1000个字节的样本(如果文件不足1000字节,read会提前结束),在样本中比较换行符的种类。如果含 'rn‘ 则是 CRLF 格式,否则是 CR 或 LF。
批量处理的效果如下:
测试代码如下:
# python check_file_encoding.py *
import
chardet
import
argparse
import
glob
import
os
import
platform
import
sys
def
change_default_encoding():
'''判断是否在
windows
git-bash 下运行,是则使用 utf-8 编码'''
if
platform.system() == 'Windows':
terminal
= os.environ.get('TERM')
if
terminal and 'xterm' in terminal:
sys
.stdout.reconfigure(encoding='utf-8')
def
is_file(file_path):
return
os.path.isfile(file_path)
def
detect_file_encoding(file_path):
with
open(file_path, 'rb') as file:
detector
= chardet.universaldetector.UniversalDetector()
for
line in file:
detector
.feed(line)
if
detector.done:
break
detector
.close()
return
detector.result['encoding']
def
check_crlf_ending(file_path):
with
open(file_path, 'rb') as file:
line
= file.read(1000)
# print(repr(line))
if
b'rn' in line or b'rx00n' in line:
return
'CRLF'
if
b'r' in line:
return
'CR'
return
'LF'
def
check_file_encodings(files):
for
file_path in files:
if
is_file(file_path):
encoding
= detect_file_encoding(file_path)
ending
= check_crlf_ending(file_path)
formatted_file_path
=
"{:<20}"
.format(file_path)
(
f
"{formatted_file_path}t编码: {encoding if encoding else '无法确定'}t换行: {ending if ending else '无法确定'}"
)
def
main():
parser
= argparse.ArgumentParser(description='Check file encodings')
parser
.add_argument(
'
files
', nargs='+', help='File paths to check. You can use * for wildcard expansion.')
args
= parser.parse_args()
# 使用 glob 模块进行通配符扩展
expanded_files
=
pattern) if is_file(file_path)]
check_file_encodings
(expanded_files)
if
__name__ ==
"__main__"
:
change_default_encoding
()
main
()
全文完。
如果转发本文,文末务必注明:“转自微信公众号:生有可恋”。
原文始发于微信公众号(生有可恋):什么是回车
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论