Excel比较两个csv文件并显示差异

0 投票
2 回答
5377 浏览
提问于 2025-04-16 18:42

我想比较两大堆csv文件,或者一个csv文件和一个.txt文件。我“觉得”为了简单起见,可能需要把.txt文件转换成csv文件,但这可能不是必须的。我想用Excel、C++或者Python来完成这个任务。我需要把一个“接受的”数值列表和一个测量得到的列表进行比较,找出它们之间的差异。如果有差异的话,Excel可能是最简单的方法,但Python或C++也可能同样有效。这不是作业,所以不用担心这些。任何代码建议和模板都非常感谢,或者提供一些网站链接。

编辑 1

我读过关于Python的difflib或者differ类的内容,但不太清楚怎么用,可能也超出了我想要的范围。

编辑 2

这两个文件都会有一系列的列(列之间没有画线之类的),在这些“命名”的列下面会有数字。我需要比较文件一的第一列第一行的数字和文件二的第一列第一行的数字,如果有差异,就把这个差异显示在另一个csv文件里。

2 个回答

1

你不需要写代码,可以通过文本编辑器里的替换功能,把两个文件中的分隔符(比如空格或逗号)弄成一样的,然后用TortoiseSVN的图形化对比工具来比较这两个文件的不同。你可以在这里找到TortoiseSVN: http://tortoisesvn.net/

2

你可以使用ADO(ODBC/JET/OLEDB文本驱动程序)把“不错的” .txt/.csv/.tab/.flr 文件当作SQL数据库中的表来处理,这在任何支持COM的语言中都可以实现。这样,你就可以利用SQL的强大功能来进行比较,比如使用DISTINCT、GROUP、(LEFT) JOINS等。

关于你的评论,补充一下:

这是你的问题,我不想强迫你去做你不想做的事情。不过,如果你需要比较表格数据,SQL是一个很好的(可能是最好的)工具。作为证据,这里有一个脚本的输出,它可以找出两个.txt文件之间的差异:

======= The .txt files to play with
------- file1.txt
"AC";"AM"
40000;-19083,00
40100;20000,00
40200;350004,00
40300;3498,99

------- file2.txt
"AC";"AM"
40000;-19083,00
40300;3498,99
40105;-234567,00
40200;350,00

======= Some diagnostic SQL
------- <NULL> indicates: In F1 but not in F2 (LEFT JOIN)
SELECT T1.AC, T1.AM, T2.AM FROM [file1.txt] AS T1 LEFT JOIN [file2.txt] AS T2 ON (T1.AC =
T2.AC)
------- Result
AC      File1   File2
40000   -19083  -19083
40100   20000   <NULL>
40200   350004  350
40300   3498,99 3498,99

------- <NULL> indicates: Not in the other file (LEFT JOIN, UNION)
SELECT T1.AC, T1.AM, T2.AM FROM [file1.txt] AS T1 LEFT JOIN [file2.txt] AS T2 ON (T1.AC =
T2.AC) UNION SELECT T2.AC, T1.AM, T2.AM FROM [file2.txt] AS T2 LEFT JOIN [file1.txt] AS T1
 ON (T1.AC = T2.AC)
------- Result
AC      File1   File2
40000   -19083  -19083
40100   20000   <NULL>
40105   <NULL>  -234567
40200   350004  350
40300   3498,99 3498,99

------- the problems: missing, different values
SELECT T1.AC, T1.AM, T2.AM FROM [file1.txt] AS T1 LEFT JOIN [file2.txt] AS T2 ON (T1.AC =
T2.AC) WHERE T2.AM IS NULL OR T1.AM <> T2.AM UNION SELECT T2.AC, T1.AM, T2.AM FROM [file2.
txt] AS T2 LEFT JOIN [file1.txt] AS T1 ON (T1.AC = T2.AC) WHERE T1.AM IS NULL OR T1.AM <>
T2.AM
------- Result
AC      File1   File2
40100   20000   <NULL>
40105   <NULL>  -234567
40200   350004  350

进一步补充:

这篇文章讲的是ADO和文本文件;在你的电脑上找一个文件 adoNNN.chm(NNN=版本号,比如210);这本关于ADO也很不错。

你可以使用Access或OpenOffice Base来实验一下SQL语句,应用于一个链接/引用的(而不是导入的!)文本数据库。

一旦你掌握了最初的难关:连接到数据库,也就是连接到一个包含文件的文件夹和一个schema.ini文件来定义文件=表的结构,写脚本/程序就会变得简单。

上面的输出是通过以下方式生成的:

  Const adClipString = 2

  Dim oFS  : Set oFS = CreateObject( "Scripting.FileSystemObject" )
  Dim sDir : sDir    = oFS.GetAbsolutePathName( ".\txt" )
  Dim oDB  : Set oDb = CreateObject( "ADODB.Connection" )
  oDB.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sDir & ";Extended Properties=""text"""
  Dim sSQL
  Dim sFiNa
  WScript.Echo "=======", "The .txt files to play with"
  For Each sFiNa In Array( "file1.txt", "file2.txt"  )
      WScript.Echo "-------", sFiNa
      WScript.Echo oFS.OpenTextFile( "txt\" & sFiNa ).ReadAll()
  Next

  WScript.Echo "=======", "Some diagnostic SQL"
  Dim aSQL
  For Each aSQL In Array( _
       Array(   "<NULL> indicates: In F1 but not in F2 (LEFT JOIN)" _
              , Join( Array( _
                     "SELECT T1.AC, T1.AM, T2.AM FROM" _
                   , "[file1.txt] AS T1" _
                   , "LEFT JOIN [file2.txt] AS T2 ON (T1.AC = T2.AC)" _
                ), " " ) ) _
     , Array(   "<NULL> indicates: Not in the other file (LEFT JOIN, UNION)" _
              , Join( Array( _
                     "SELECT T1.AC, T1.AM, T2.AM FROM" _
                   , "[file1.txt] AS T1" _
                   , "LEFT JOIN [file2.txt] AS T2 ON (T1.AC = T2.AC)" _
                   , "UNION" _
                   , "SELECT T2.AC, T1.AM, T2.AM FROM" _
                   , "[file2.txt] AS T2" _
                   , "LEFT JOIN [file1.txt] AS T1 ON (T1.AC = T2.AC)" _
                ), " " ) ) _
     , Array(   "the problems: missing, different value" _
              , Join( Array( _
                     "SELECT T1.AC, T1.AM, T2.AM FROM" _
                   , "[file1.txt] AS T1" _
                   , "LEFT JOIN [file2.txt] AS T2 ON (T1.AC = T2.AC)" _
                   , "WHERE T2.AM IS NULL OR T1.AM <> T2.AM" _
                   , "UNION" _
                   , "SELECT T2.AC, T1.AM, T2.AM FROM" _
                   , "[file2.txt] AS T2" _
                   , "LEFT JOIN [file1.txt] AS T1 ON (T1.AC = T2.AC)" _
                   , "WHERE T1.AM IS NULL OR T1.AM <> T2.AM" _
                ), " " ) ) _
     )
     sSQL = aSQL( 1 )
     WScript.Echo "-------", aSQL( 0 )
     WScript.Echo sSQL
     Dim oRS : Set oRS = oDB.Execute( sSQL )
     WScript.Echo "------- Result"
     WScript.Echo Join( Array( "AC", "File1", "File2" ), vbTab )
     WScript.Echo oRS.GetString( adClipString, , vbTab, vbCrLf, "<NULL>" )
  Next
  oDB.Close

如果你删除/忽略掉多余的部分(创建SQL语句、诊断输出),实际上只需要6行代码。

  Dim oDB  : Set oDb = CreateObject( "ADODB.Connection" )
  oDB.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sDir & ";Extended Properties=""text"""
  sSQL = "..."
  Dim oRS : Set oRS = oDB.Execute( sSQL )
  WScript.Echo oRS.GetString( adClipString, , vbTab, vbCrLf, "<NULL>" )
  oDB.Close

这些代码可以很容易地“移植”到任何支持COM的语言,因为ADO对象处理了所有繁重的工作。当你想保存结果集时,.GetString方法非常方便:只需调整分隔符/定界符/空值参数,然后将其写入文件。

  oFS.CreateTextFile( ... ).WriteLine oRS.GetString( _
    adClipString, , ",", vbCrLf, ""
  )

(别忘了在你的schema.ini中为那个表添加定义)。当然,你也可以使用“SELECT/INSERT INTO”,但这样的语句可能不容易正确通过ADO文本驱动程序的解析。

关于计算的补充:

从一个5 x 2的主文件/批准文件开始,内容包括:

Num0    Num1    Num2    Num3    Num4
7,6     6,1     3,8     0,9     8,9
0,9     9,4     4,7     8,8     9,9

将其转换为expected.txt

Num0    Num1    Num2    Num3    Num4    Spot
7,6     6,1     3,8     0,9     8,9     1
0,9     9,4     4,7     8,8     9,9     2

通过添加Spot列,使其符合

[expected.txt]
ColNameHeader=True
CharacterSet=1252
Format=Delimited(;)
Col1=Num0 Float
Col2=Num1 Float
Col3=Num2 Float
Col4=Num3 Float
Col5=Num4 Float
Col6=Spot Integer

在你的schema.ini文件中。同样,将一个测量文件像:

Num0    Num1    Num2    Num3    Num4
7,1     1,1     3,8     0,9     8,9
0,9     9,4     4,7     8,8     9,9

转换为measured.txt

Num0    Num1    Num2    Num3    Num4    Spot
7,1     1,1     3,8     0,9     8,9     1
0,9     9,4     4,7     8,8     9,9     2

应用

  sSQL = Join( Array( _
         "SELECT E.Num0 - M.Num0 AS Dif0" _
      ,       ", E.Num1 - M.Num1 AS Dif1" _
      ,       ", E.Num2 - M.Num2 AS Dif2" _
      ,       ", E.Num3 - M.Num3 AS Dif3" _
      ,       ", E.Num4 - M.Num4 AS Dif4" _
      ,       ", E.Spot          AS Spot" _
      ,  "FROM [expected.txt] AS E" _
      ,  "INNER JOIN [measured.txt] AS M" _
      ,  "ON E.Spot = M.Spot" _
  ), " " )

将结果集写入differences.txt

aFNames = Array( "Num0", ... "Spot" )
oFS.CreateTextFile( sFSpec ).Write _
Join( aFNames, sFSep ) & sRSep & oRS.GetString( adClipString, , sFSep, sRSep, "")

然后你会得到:

Num0    Num1    Num2    Num3    Num4    Spot
0,5     5       0       0       0       1
0       0       0       0       0       2

撰写回答