簡短的答案
現在亮起來的是真的:變了的值、冒出來的鍵、消失的條目。會淹死普通比對的格式差異和換了位置的鍵都沒了,因為比對開始之前,兩邊已經寫成了同一種拼法。
兩個頁面都沒有任何網路功能——這一點值得知道:人們拿來比對的 JSON,太多時候是憑據還躺在裡面的配置檔案。
為什麼生比 JSON 幾乎全是噪音
JSON 不在乎空白,也不給鍵的順序賦予意義。同一份文件可以是一行,也可以是四百行;鍵可以按敲下的順序排,也可以按某個庫吐出的順序排——工具改寫這兩樣從不打招呼。一邊壓縮了,一邊鋪開了;一邊手工存的,一邊出自按字母排序的序列化器:逐行比對看見的是兩個不相干的檔案。
兩個最糟的情形足以說明問題。壓縮過的檔案是一行,於是和它比對得到一條巨大無比的變更行——正確,且無用。而內容相同、順序不同的兩個檔案會比出個處處皆變,誠實的答案本該是「什麼都沒變」。
格式化器的規範形修好了什麼
兩個檔案過同一個格式化器、用同樣的設定,正是比對需要的:一份文件一種拼法。
- 同樣的縮排讓每個鍵各佔一行:比對於是逐行工作,它的逐詞標記也能指著一行裡唯一變了的那個值。
- 排好序的鍵讓兩邊同序,順序就不再是差異。排序按鍵讀起來的樣子,不按碼位——
item2排在item10前——並且兩邊施加得一模一樣。 - 其餘分毫不動。這個格式化器讓數字保持你寫下的每一位,保留重複的鍵而不是替你裁決:規範化自己變不出差異來。格式化器指南解釋了這為什麼比理應的更稀罕。
一句誠實的但書:排序後的輸出是鍵挪了位的文件。要是下游某個工具在乎鍵的順序——在乎的不多,但存在——就把排序的副本當作被比對的東西,而不是原件的替身。
讀結果,並帶走它
比對把刪掉的行標在左邊、新增的行標在右邊,變了的行裡再把不同的詞高亮出來:在規範形上,那通常就是從 false 挪到 true 的那一個值。沒變的中段摺疊成一個數字,兩千行的配置改了三處,讀起來就是三小段。
下載下來的是統一格式的補丁,一個 .patch——程式碼評審看得懂的格式。它描述的是規範形,而那通常正是評審想要的:只有改動,沒有重排。
同一套做法對兩個頁面會說的其他東西同樣有效。YAML 和 XML 用同樣的方法化成規範形;來源不同、形狀相同的兩個檔案,比對的忽略開關——空白、大小寫、空行——就是同一想法的輕量版。
如果你每週都做這件事
格式化兩次、貼上兩次:步驟住在兩個頁面上,因為每頁只做一件事,而且各自都能證明你貼的東西哪裡也沒去。但兩個都是開源的:MIT 許可證,零依賴的 ES 模組——格式化器的解析器保住鍵序和數位,比對是 Myers 演算法——各配一份講明白它的 README。
要是這已是你每天的一部分,把編碼智慧體指向程式碼儲存庫,請它做一頁兩個框、邊比對邊規範化的頁面:parseJson、printJson 和 compareText 只隔三個 import。這些模組寫出來就是給人讀的,把它們搬走,正是這份許可證存在的目的。