7

Tôi gặp sự cố khi so sánh hai tệp. Về cơ bản, những gì tôi muốn làm là một diff UNIX-like giữa hai tập tin, ví dụ:Tạo sự khác biệt "mờ" của hai tệp trong Python, với so sánh gần đúng của phao nổi

$ diff -u trái tập tin phải tập

Tuy nhiên hai tập tin của tôi chứa nổi; và bởi vì các tệp này được tạo trên các kiến ​​trúc riêng biệt (nhưng tính toán cùng một thứ), các giá trị thả nổi không giống nhau (chúng có thể khác nhau, ví dụ, 1e-10). Nhưng những gì tôi tìm kiếm bằng cách 'diffing' các tập tin là để tìm thấy những gì tôi coi là sự khác biệt đáng kể (ví dụ sự khác biệt là nhiều hơn 1e-4); trong khi sử dụng lệnh UNIX khác, tôi nhận được gần như tất cả các dòng của tôi có chứa các giá trị nổi khác nhau! Đó là vấn đề của tôi: làm thế nào tôi có thể nhận được một kết quả khác biệt như 'diff -u' cung cấp, nhưng với ít hạn chế về so sánh của phao nổi?

Tôi nghĩ rằng tôi sẽ viết một kịch bản Python để làm điều đó, và phát hiện ra difflib mô-đun cung cấp so sánh tương tự. Nhưng tài liệu tôi tìm thấy giải thích cách sử dụng nó như là (thông qua một phương thức đơn), và giải thích các đối tượng bên trong, nhưng tôi không thể tìm thấy bất cứ điều gì liên quan đến cách tùy chỉnh một đối tượng difflib để đáp ứng nhu cầu của tôi (như viết lại chỉ phương pháp so sánh hoặc như vậy) ... Tôi đoán một giải pháp có thể là để lấy sự khác biệt thống nhất, và phân tích nó 'thủ công' để loại bỏ sự khác biệt 'sai' của tôi, bởi đây không phải là thanh lịch; Tôi muốn sử dụng khung đã có sẵn.

Vì vậy, không ai biết cách tùy chỉnh lib này để tôi có thể làm những gì tôi tìm kiếm? Hoặc ít nhất là chỉ cho tôi đúng hướng ... Nếu không có trong Python, có thể một kịch bản lệnh shell có thể thực hiện công việc đó?

Bất kỳ trợ giúp nào sẽ được đánh giá rất nhiều! Cảm ơn trước cho câu trả lời của bạn!

+1

Có lẽ bạn cũng thích: [Tốt Python module để so sánh chuỗi mờ ?] (http://stackoverflow.com/questions/682367/good-python-modules-for-fuzzy-string-comparison) – miku

+0

một lựa chọn đơn giản hơn sẽ là xử lý trước định dạng tệp và định dạng chính xác đến độ chính xác mong muốn –

+0

Vui lòng đăng một vài dòng tương ứng từ các tệp nhập mẫu? – smci

Trả lời

4

Trong trường hợp của bạn, chúng tôi chuyên general case: trước khi chúng tôi chuyển nội dung vào difflib, chúng tôi cần phát hiện và xử lý riêng các dòng có chứa phao. Đây là một cách tiếp cận cơ bản, nếu bạn muốn tạo ra các vùng đồng bằng, các dòng ngữ cảnh, vv bạn có thể xây dựng trên đó. Lưu ý, việc so sánh các float trôi nổi dễ dàng hơn so với các chuỗi float thực tế hơn là các chuỗi (mặc dù bạn có thể mã một cột từng cột khác nhau và bỏ qua các ký tự sau 1-e4).

import re 

float_pat = re.compile('([+-]?\d*\.\d*)') 
def fuzzydiffer(line1,line2): 
    """Perform fuzzy-diff on floats, else normal diff.""" 
    floats1 = float_pat.findall(line1) 
    if not floats1: 
     pass # run your usual diff() 
    else: 
     floats2 = float_pat.findall(line2) 
     for (f1,f2) in zip(floats1,floats2): 
      (col1,col2) = line1.index(f1),line2.index(f2) 
      if not fuzzy_float_cmp(f1,f2): 
       print "Lines mismatch at col %d", col1, line1, line2 
      continue 
    # or use a list comprehension like all(fuzzy_float_cmp(f1,f2) for f1,f2 in zip(float_pat.findall(line1),float_pat.findall(line2))) 
    #return match 

def fuzzy_float_cmp(f1,f2,epsilon=1e-4): 
    """Fuzzy-compare two strings representing floats.""" 
    float1,float2 = float(f1),float(f2) 
    return (abs(float1-float2) < epsilon) 

Một số xét nghiệm:

fuzzydiffer('text: 558.113509766 +23477547.6407 -0.867086648057 0.009291785451', 
'text: 558.11351 +23477547.6406 -0.86708665 0.009292000001') 

và như một phần thưởng, đây là một phiên bản làm nổi bật cột diffs:

import re 

float_pat = re.compile('([+-]?\d*\.\d*)') 
def fuzzydiffer(line1,line2): 
    """Perform fuzzy-diff on floats, else normal diff.""" 
    floats1 = float_pat.findall(line1) 
    if not floats1: 
     pass # run your usual diff() 
    else: 
     match = True 
     coldiffs1 = ' '*len(line1) 
     coldiffs2 = ' '*len(line2) 
     floats2 = float_pat.findall(line2) 
     for (f1,f2) in zip(floats1,floats2): 
      (col1s,col2s) = line1.index(f1),line2.index(f2) 
      col1e = col1s + len(f1) 
      col2e = col2s + len(f2) 
      if not fuzzy_float_cmp(f1,f2): 
       match = False 
       #print 'Lines mismatch:' 
       coldiffs1 = coldiffs1[:col1s] + ('v'*len(f1)) + coldiffs1[col1e:] 
       coldiffs2 = coldiffs2[:col2s] + ('^'*len(f2)) + coldiffs2[col2e:] 
      #continue # if you only need to highlight first mismatch 
     if not match: 
      print 'Lines mismatch:' 
      print ' ', coldiffs1 
      print '< ', line1 
      print '> ', line2 
      print ' ', coldiffs2 
     # or use a list comprehension like 
     # all() 
     #return True 

def fuzzy_float_cmp(f1,f2,epsilon=1e-4): 
    """Fuzzy-compare two strings representing floats.""" 
    print "Comparing:", f1, f2 
    float1,float2 = float(f1),float(f2) 
    return (abs(float1-float2) < epsilon)