[Json.NET] DeserializeObject 檔案字串時遇到的錯誤 (Solved)

ZERO WIDTH NO-BREAK SPACE

今天在使用 Json.NET 處理讀取到的 Json 文字檔案,要反序列化為 Object 物件資料時遇到了一個錯誤:

1
Unexpected character encountered while parsing value: e. Path '', line 0, position 0.

後來找出了原因並解決了,是關於檔案在某些文字編輯器儲存時會留下的 BOM 字元,導致 Json 格式錯誤。

錯誤的詳細過程

Json.NET 我在使用上最常用到的兩個功能,分別是 JsonConvert.SerializeObjectJsonConvert.DeserializeObject,用於將物件資料序列化為 Json 字串,或者反過來用 Json 字串回復物件資料。

這天在 Unity 是使用 JsonConvert.DeserializeObject 從外部讀入的 Json 文字檔案,要實作成可以外部更新的文字相關系統時,遭遇到了無法 Parsing 的例外錯誤。

1
Unexpected character encountered while parsing value: e. Path '', line 0, position 0.

因為檔案是來自外部文字編輯器編輯而成,所以格式錯誤是很容易發生的,但是這次我將檔案字串放入其他 Json 專屬編輯器,卻都沒有出現錯誤警告,讓人困惑。

線上分析字串的工具

後來對於格式內容沒轍,改轉向研究字元編碼造成的問題。

分享一個我覺得相當好用的線上工具,可以用來檢查字串的很多細節:

Unicode code converter

不過編碼沒有發現問題,到是發現字元數量跟預期的不太相同。於利用上述轉換工具中的 View in UniView 功能,可以檢查所有字元的細節,這才發現了 U+FEFF 字元的存在。

ZERO WIDTH NO-BREAK SPACE

解決方式在 C# 中相當容易,一段 str = str.Replace ("\uFEFF", ""); 移除所有 U+FEFF 即可。

JsonConvert.DeserializeObject 總算是順利運作了!

一些背後的原理

在一些文字編輯器輸出的文字檔開頭,會置入一個稱作Byte order mark,簡稱 BOM 的字元作為文件開頭。目的是為了分辨與紀錄後續字元的編碼方式,同樣在一些 php 網頁中也可能存在。

而在 C# 讀入檔案後,並不會忽略這些標記用的特殊字元,而是用一個 zero width no-break space 字元代替,即為 U+FEFF 字元。

雖然有這個字元存在,但直接印出字串的時候,並不會留下空白或任何記號,而是完完全全的看不見,所以處理起來格外容易被忽略。過去在撰寫網路爬蟲時也被相似的字元狠狠的懲罰過,而這次又遇見了類似的問題。

這可不只是魔鬼藏在細節裡,而是確確實實看不見的鬼魂,未來讀檔或下載文件檔來處理時也還會在相遇吧!

參考