解決NSData中包含非法UTF-8編碼

weixin_34087301發表於2017-01-11

我們開發中常會遇上將NSData轉換為NSString,或通過NSJSONSerialization解析JSON的場景,一旦NSData中包含非法的UTF-8編碼,那麼結果將是返回nil,但這樣的結果並不符合我們預期,因為可能這其中僅僅只是一個編碼錯誤,我們更希望將錯誤編碼丟棄或替換為錯誤字元.

在Google上找了一圈,有人也實現了這樣的方法,但個人覺得寫得不夠嚴謹,容錯性也不太好,索性自己寫一個吧,嚴格按照RFC3629的標準.

UTF-8是一種變長的編碼,針對不同長度的位元組有固定的格式,在RFC3629規範中最多隻能四個位元組,且對範圍有區間有要求,更多相關介紹請跳轉維基百科UTF-8詞條(跳轉地址):

1位元組0xxxxxxx

2位元組110xxxxx10xxxxxx

3位元組1110xxxx10xxxxxx10xxxxxx

4位元組11110xxx10xxxxxx10xxxxxx10xxxxxx

按照這樣的規則寫了一個NSData的擴充套件方法,見程式碼:

@implementationNSData(UTF8)

- (NSData*)UTF8Data

{

//儲存結果

NSMutableData*resData = [[NSMutableDataalloc] initWithCapacity:self.length];

//無效編碼替代符號(常見 � □ ?)

NSData*replacement = [@"�"dataUsingEncoding:NSUTF8StringEncoding];

uint64_t index =0;

constuint8_t *bytes =self.bytes;

while(index

{

uint8_t len =0;

uint8_t header = bytes[index];

//單位元組

if((header&0x80) ==0)

{

len =1;

}

//2位元組(並且不能為C0,C1)

elseif((header&0xE0) ==0xC0)

{

if(header !=0xC0&& header !=0xC1)

{

len =2;

}

}

//3位元組

elseif((header&0xF0) ==0xE0)

{

len =3;

}

//4位元組(並且不能為F5,F6,F7)

elseif((header&0xF8) ==0xF0)

{

if(header !=0xF5&& header !=0xF6&& header !=0xF7)

{

len =4;

}

}

//無法識別

if(len ==0)

{

[resData appendData:replacement];

index++;

continue;

}

//檢測有效的資料長度(後面還有多少個10xxxxxx這樣的位元組)

uint8_t validLen =1;

while(validLen < len && index+validLen

{

if((bytes[index+validLen] &0xC0) !=0x80)

break;

validLen++;

}

//有效位元組等於編碼要求的位元組數表示合法,否則不合法

if(validLen == len)

{

[resData appendBytes:bytes+index length:len];

}else

{

[resData appendData:replacement];

}

//移動下標

index += validLen;

}

returnresData;

}

@end

在Github上的連結地址:https://github.com/tanhaogg/THCategory

相關文章