沒想到規則意外的簡單,因為我不須知道太詳細的細節,只需知道幾個重點:
- 只要是0開頭的byte就表示是ascii編碼,也就是0xxxxxxx後面的七碼x相容於傳統ascii編碼
- 非ascii編碼,一律以1開頭再接0,並且最少兩個1
- 1的數量指出這個字是由幾個byte所組成,如1110xxxxx表示這個字要3個byte
- 其後每個子byte都為10開頭
- 最多每個字4個byte
- 依照規格,只要有非0、非110、非1110、非11110開頭的byte,就是非utf-8
- 110開頭的byte,需檢查是否有下一個byte,或底下一個byte是否為10開頭
- 1110開頭的byte,需檢查是否有下兩個byte,或底下兩個byte是否皆為10開頭
- 11110開頭的byte,需檢查是否有下三個byte,或底下三個byte是否皆為10開頭
- 全部byte跑完之後的指標是否等於檔案長度
底下就是程式碼了:
/// <summary> /// 檢查是否符合utf-8編碼的核心程式 /// </summary> /// <param name="bytes">文字原始byte陣列</param> /// <returns></returns> private static bool _IsUtf8(byte[] bytes) { int i = 0; int size = bytes.Length; //跑每一個byte,需要每個byte都符合utf-8編碼規則才算是utf-8編碼 while (i < size) { int step = 0; if ((bytes[i] & 0x80) == 0x00) { //utf-8的ascii字元,為0開頭,OK跑下一個位元 step = 1; } else if ((bytes[i] & 0xE0) == 0xC0) { /* 110xxxxx & 11100000 (0xE0) ---------- 11000000 (0xC0) */ //utf-8使用2bytes編碼格式為 110xxxxx 10xxxxxx //如果是110xxxxx開頭,要判斷下個位元是否是10開頭 //如果下一個已經沒有資料了,表示這不是utf-8編碼 if (i + 1 >= size) { return false; } //如果下個位元不是10開頭,也表示這不是utf-8編碼 if ((bytes[i + 1] & 0xC0) != 0x80) { return false; } //繼續跑下2個 step = 2; } else if ((bytes[i] & 0xF0) == 0xE0) { /* 1110xxxx & 11110000 (0xF0) ---------- 11100000 (0xE0) */ //utf-8使用3bytes編碼格式為 1110xxxx 10xxxxxx 10xxxxxx //所以如果是1110xxxx開頭,要判斷下兩個byte是否都是10開頭 //如果下兩個已經沒有資料了,表示不是utf-8編碼 if (i + 2 >= size) { return false; } //如果下兩個位元不是10開頭,也不是utf-8編碼 if ((bytes[i + 1] & 0xC0) != 0x80) { return false; } if ((bytes[i + 2] & 0xC0) != 0x80) { return false; } //繼續跑下3個 step = 3; } else if ((bytes[i] & 0xF8) == 0xF0) { /* 11110xxx & 11111000 (0xF8) ---------- 11110000 (0xF0) */ //utf-8使用4bytes編碼格式為 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx //所以如果是11110xxx開頭,要判斷下3個byte是否都是10開頭 //如果下3個已經沒有資料了,表示不是utf-8編碼 if (i + 3 >= size) { return false; } //如果下3個位元不是10開頭,也不是utf-8編碼 if ((bytes[i + 1] & 0xC0) != 0x80) { return false; } if ((bytes[i + 2] & 0xC0) != 0x80) { return false; } if ((bytes[i + 3] & 0xC0) != 0x80) { return false; } //繼續跑下4個 step = 4; } else { //如果都不是當然就不是utf-8了 return false; } i += step; } if (i == size) { return true; } return false; }
參考資料:
沒有留言:
張貼留言