C# char 65279 BOM,解決字符串視覺上相同,但字符串比較失敗的問題

BOM

去百度看了一下,原來是文件bom標記位(BOM: byte order mark : 字節順序標記)
之前爲了方便測試一些文件數據,用了notepad.exe去創建 .txt,結果讀取出來的字符和程序中的死活不相同。
就是因爲bom標記導致的。

什麼是BOM?

網上搜索:
百度科的BOM

Unicode規範中的BOM
Unicode規範中有一個BOM的概念。BOM——Byte Order Mark,就是字節序標記。在這裏找到一段關於BOM的說明:
在UCS 編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應該出現在實際傳輸中。UCS規範建議我們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者收到FEFF,就表明這個字節流是Big-Endian的;如果收到FFFE,就表明這個字節流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
UTF-8不需要BOM來表明字節順序,但可以用BOM來表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。所以如果接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。
Windows就是使用BOM來標記文本文件的編碼方式的。
另外unicode網站的FAQ-BOM詳細介紹了BOM。官方的自然權威,不過是英文的,看起來比較費勁。
UTF-8編碼的文件中,BOM佔三個字節。如果用記事本把一個文本文件另存爲UTF-8編碼方式的話,用UE打開這個文件,切換到十六進制編輯狀態就可以看到開頭的EF BB BF了。這是個標識UTF-8編碼文件的好辦法,軟件通過BOM來識別這個文件是否是UTF-8編碼,很多軟件還要求讀入的文件必須帶BOM。可是,還是有很多軟件不能識別BOM。我在研究Firefox的時候就知道,在Firefox早期的版本里,擴展是不能有BOM的,不過Firefox 1.5以後的版本已經開始支持BOM了。如今又發現,PHP也不支持BOM。
PHP在設計時就沒有考慮BOM的問題,也就是說他不會忽略UTF-8編碼的文件開頭BOM的那三個字符。由於必須在<?或者<?php後面的代碼纔會作爲PHP代碼執行,所以這三個字符將會直接輸出。如果插件的文件有這個問題,將會導致在後臺頁面裏激活或者不激活插件後顯示白屏,如果是模版文件有這個問題,將會導致這三個字符直接輸出,造成頁面上方有一個小空行。國外的英文插件和模版一般都是用的ASCⅡ碼的編碼方式,不會有BOM,只有國內的插件和模版會由於作者的不知情造成問題。還有,大家修改模版的時候,由於輸出頁面使用UTF-8編碼,那麼修改模版的時候如果有加入中文字符的話,必須把文件轉成UTF-8編碼才能正常顯示,這個時候如果所使用的編輯器自動加上了BOM的話,將會造成在頁面上輸出這三個字符,顯示效果就要看瀏覽器了,一般是一個空行或是一個亂碼。

一般我們遇到BOM標記都是醬紫導致(或者是我們的一個API導出文件時,默認參數就是With BOM):

是utf-8用記事本編輯代碼保存的錯誤,使代碼在保存的時候帶上了BOM。 最好寫代碼的時候用編譯器編寫,不要用記事本編寫代碼。
出現出錯後,點擊下面的網址下載一個UltraEdit或editplus

說得比較清楚的還是stackoverflow的一篇文件

It’s a zero-width no-break space.
It’s more commonly used as a byte-order mark (BOM).

解決方法

用:Sublime、EditorPlus、UltraEditor、Notepad++等文本編輯來輸入文本,保存就可以了。
我記得其中一個編輯器(忘記是哪個了)可以save with encoding…->
* no bom utf8
* with bom utf8
選第一個:no bom utf8就可以了。

UTF8編碼的BOM頭代碼處理(原文),其他編碼不一定能這樣處理:

byte[] buffer = ...;
byte[] bomBuffer = new byte[] { 0xef, 0xbb, 0xbf }; // 0xef:239, 0xbb:187, oxbf:191

if (buffer[0] == bomBuffer[0]
    && buffer[1] == bomBuffer[1]
    && buffer[2] == bomBuffer[2])
{
    return Encoding.UTF8.GetString(buffer, 3, buffer.Length - 3);
}

return Encoding.UTF8.GetString(buffer);

Unicode的話,FEFF或FFFE開頭的都是BOM,FEFF是Big-Endian(高位靠左), FFFE是Little-Endian(地位靠右)

現象:

vs中watch, variable等查看兩個字符:a == “ab”; b == “ab”;

結果:a == b 一直都是false
string.Equals(a,b) == false

視覺上:a=”ab”, b=”ab”都是”ab”沒有問題啊。
然後發現:a.Length == 3, b.Length == 2

接着輸出:
a[0] == ” // 一個什麼都看不到的字符
a[1] == ‘a’
a[2] == ‘b’

b[0] == ‘a’
b[1] == ‘b’

因爲a[0]視覺上不知道是什麼字符

將BOM揪出來

((int)a[0]) == 65279

然後就直接:百度、必應:C# 65279

看VSC的運行效果圖:

看VSC的運行效果圖

然後就沒然後了。。。
嗯,告一段落。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章