我在git文件中遇到了一个令人讨厌的CRLF / LF冲突,可能是从Windows机器提交的。是否存在跨平台方式(最好是在Python中)来检测通过文件占主导地位的新行类型?
我有这段代码(基于https://stackoverflow.com/a/10562258/239247的想法):
import sys
if not sys.argv[1:]:
sys.exit('usage: %s <filename>' % sys.argv[0])
with open(sys.argv[1],"rb") as f:
d = f.read()
crlf, lfcr = d.count('\r\n'), d.count('\n\r')
cr, lf = d.count('\r'), d.count('\n')
print('crlf: %s' % crlf)
print('lfcr: %s' % lfcr)
print('cr: %s' % cr)
print('lf: %s' % lf)
print('\ncr-crlf-lfcr: %s' % (cr - crlf - lfcr))
print('lf-crlf-lfcr: %s' % (lf - crlf - lfcr))
print('\ntotal (lf+cr-2*crlf-2*lfcr): %s\n' % (lf + cr - 2*crlf - 2*lfcr))
但是它会使统计信息错误(对于this file):
crlf: 1123
lfcr: 58
cr: 1123
lf: 1123
cr-crlf-lfcr: -58
lf-crlf-lfcr: -58
total (lf+cr-2*crlf-2*lfcr): -116
答案 0 :(得分:2)
import sys
def calculate_line_endings(filename):
cr = lf = crlf = lfcr = 0
for line in open(filename, "rb"):
if line.endswith('\r\n'):
crlf += 1
elif line.endswith('\n\r'):
lfcr += 1
elif line.endswith('\r'):
cr += 1
elif line.endswith('\n'):
lf += 1
print('crlf: %s' % crlf)
print('lfcr: %s' % lfcr)
print('cr: %s' % cr)
print('lf: %s' % lf)
if __name__ == '__main__':
if len(sys.argv) == 1:
sys.exit('usage: %s <filename>' % sys.argv[0])
else:
calculate_line_endings(sys.argv[1])
为您的文件提供输出
crlf: 1123
lfcr: 0
cr: 0
lf: 0
够了吗?
答案 1 :(得分:1)
发布的代码无法正常运行因为计数器正在计算文件中的字符数 - 它不会查找\r\n
和\n\r
等字符对。
这里有一些Python 2.6代码,它使用正则表达式查找4个EOL标记\r\n
,\n\r
,\r
和\n
的每次出现。诀窍是在查找单个字符EOL标记之前查找\r\n
和\n\r
对。
出于测试目的,它会创建一些随机文本数据;在我注意到你的测试文件链接之前我写了这个。
#!/usr/bin/env python
''' Find and count various line ending character combinations
From http://stackoverflow.com/q/29695861/4014959
Written by PM 2Ring 2015.04.17
'''
import random
import re
from itertools import groupby
random.seed(42)
#Make a random text string containing various EOL combinations
tokens = list(2*'ABCDEFGHIJK ' + '\r\n') + ['\r\n', '\n\r']
datasize = 300
data = ''.join([random.choice(tokens) for _ in range(datasize)])
print repr(data), '\n'
#regex to find various EOL combinations
pat = re.compile(r'\r\n|\n\r|\r|\n')
eols = pat.findall(data)
print eols, '\n'
grouped = [(len(list(group)), key) for key, group in groupby(sorted(eols))]
print sorted(grouped, reverse=True)
<强>输出强>
'FAHGIG\rC AGCAFGDGEKAKHJE\r\nJCC EKID\n\rKD F\rEHBGICGCHFKKFH\r\nGFEIEK\n\rFDH JGAIHF\r\n\rIG \nAHGDHE\n G\n\rCCBDFK BK\n\rC\n\r\rAIHDHFDAA\r\n\rHCF\n\rIFFEJDJCAJA\r\n\r IB\r\r\nCBBJJDBDH\r FDIFI\n\rGACDGJEGGBFG\n\rBGGFD\r\nDBJKFCA BIG\n\rC J\rGFA HG\nA\rDB\n\r \n\r\n EBF BK\n\rHJA \r\n\n\rDIEI\n\rEDIBEC E\r\nCFEGGD\rGEF EC\r\nFIG GIIJCA\n\r\n\rCFH\r\n\r\rKE HF\n\rGAKIG\r\nDDCDHEIFFHB\n C HAJFHID AC\r'
['\r', '\r\n', '\n\r', '\r', '\r\n', '\n\r', '\r\n', '\r', '\n', '\n', '\n\r', '\n\r', '\n\r', '\r', '\r\n', '\r', '\n\r', '\r\n', '\r', '\r', '\r\n', '\r', '\n\r', '\n\r', '\r\n', '\n\r', '\r', '\n', '\r', '\n\r', '\n\r', '\n', '\n\r', '\r\n', '\n\r', '\n\r', '\r\n', '\r', '\r\n', '\n\r', '\n\r', '\r\n', '\r', '\r', '\n\r', '\r\n', '\n', '\r']
[(17, '\n\r'), (14, '\r'), (12, '\r\n'), (5, '\n')]
这是一个从命名文件中读取数据的版本,遵循问题中代码的模式。
import re
from itertools import groupby
import sys
if not sys.argv[1:]:
exit('usage: %s <filename>' % sys.argv[0])
with open(sys.argv[1], 'rb') as f:
data = f.read()
print repr(data), '\n'
#regex to find various EOL combinations
pat = re.compile(r'\r\n|\n\r|\r|\n')
eols = pat.findall(data)
print eols, '\n'
grouped = [(len(list(group)), key) for key, group in groupby(sorted(eols))]
print sorted(grouped, reverse=True)
答案 2 :(得分:1)
从我看到的情况来看,我建议您检查是否有以下情况:
\r\n\r\n\r\n
。按照您的代码,这将计算以下内容:
crlf: 3 -- [\r\n][\r\n][\r\n]
lfcr: 2 -- \r[\n\r][\n\r]\n
cr: 3 -- [\r]\n[\r]\n[\r]\n
lf: 3 -- \r[\n]\r[\n]\r[\n]
cr-crlf-lfcr: -2
lf-crlf-lfcr: -2
total (lf+cr-2*crlf-2*lfcr): -4
正如您所看到的\n
和\r
被crlf
和lfcr
计算了两次line.endswith()
。相反,您可以逐行阅读并计算行结尾cr
。要获得lf
和\r\n
的准确统计信息,您可以将\n\r
和{{1}}计为cr + 1和lf + 1.
答案 3 :(得分:1)
在git中处理行结尾的最佳方法是使用git配置。您可以定义在全局,特定存储库或特定文件中对行结尾必须完成的操作。在.gitattributes
文件中,您可以定义必须将每个签出转换为系统的本机行结尾,并在签入时转换回来。有关详细说明,请参阅GitHub line endings help。