2015-04-17 103 views
0

我在git文件中有一個令人討厭的CRLF/LF衝突,這個衝突很可能是從Windows機器提交的。是否有跨平臺的方式(最好用Python)來檢測文件中哪些類型的換行符占主導地位?在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

和sorrat一樣,我爲該文件獲得1123個crlf對,其他3個EOL標記爲0。 –

+0

@ PM2Ring我需要一個更好的測試文件。我認爲這個實際上包含混合的換行。 –

回答

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 

夠了嗎?

+0

這個很好。你知道open(filename,「rb」)中的行是如何正確檢測行的嗎?只是爲了解角落案例。 –

+0

對不起,我不知道。可能是[PEP-278]的原因(https://www.python.org/dev/peps/pep-0278/) – sorrat

1

發表的代碼無法正常工作bcause計數器正在計算文件中的字符 - 它不尋找像\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) 
+0

好方法。特別酷,它有測試數據進行比較。 –

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的是爲crlflfcr計數兩次。相反,您可以逐行閱讀並計算行結尾line.endswith()。要得到crlf的確切統計數據,可以將\r\n\n\r分別計爲cr + 1和lf + 1。

1

在git中處理行結束的最好方法是使用git配置。您可以定義全局,特定存儲庫或特定文件中的行結尾必須完成的操作。在.gitattributes文件中,您可以定義某些文件必須轉換爲系統的本機行結束,以便每次結帳,並在簽入時轉換回來。有關詳細說明,請參見GitHub line endings help

+0

我不想轉換任何東西,默認情況下可以讓我的文件保持原樣嗎? –

相關問題