Encoding NSInputStream中的字符串不是有效的utf8。如何转换为utf8更多';有损';

Encoding NSInputStream中的字符串不是有效的utf8。如何转换为utf8更多';有损';,encoding,utf-8,nsstring,Encoding,Utf 8,Nsstring,我有一个从服务器读取数据的应用程序。有时,数据似乎不是有效的UTF-8。如果将字节数组转换为UTF8字符串,该字符串将显示为nil。字节数组中必须有一些无效的not-UTF8字符。是否有方法将字节数组“有损”转换为UTF8,并仅过滤掉无效字符 有什么想法吗 我的代码如下所示: - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent { switch (streamEvent){ case N

我有一个从服务器读取数据的应用程序。有时,数据似乎不是有效的UTF-8。如果将字节数组转换为UTF8字符串,该字符串将显示为nil。字节数组中必须有一些无效的not-UTF8字符。是否有方法将字节数组“有损”转换为UTF8,并仅过滤掉无效字符

有什么想法吗

我的代码如下所示:

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {

switch (streamEvent){
    case NSStreamEventHasBytesAvailable:
    {
        uint8_t buffer[1024];
        int len;
        NSMutableData * inputData = [NSMutableData data];
        while ([directoryStream hasBytesAvailable]){
            len = [directoryStream read:buffer maxLength:sizeof(buffer)];
            if (len> 0) {
                [inputData appendBytes:(const void *)buffer length:len];
            }
        }
        NSString *directoryString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    }
    NSLog(@"directoryString: %@", directoryString);

    ...
有没有办法以更“有损”的方式进行转换


如您所见,我首先将数据块附加到NSData值,并在读取所有内容时将其转换为utf8。这可以防止(多字节)utf8字符被拆分,从而导致更多无效(空)utf8字符串。

它可以工作!通过结合Larme的代码片段和关于UTF-8字符大小的注释,我成功地创建了一个“有损”NSData到UTF-8 NSString的转换方法

+ (NSString *) data2UTF8String:(NSData *) data {

    // First try to do the 'standard' UTF-8 conversion 
    NSString * bufferStr = [[NSString alloc] initWithData:data
                                                 encoding:NSUTF8StringEncoding];

    // if it fails, do the 'lossy' UTF8 conversion
    if (!bufferStr) {
        const Byte * buffer = [data bytes];

        NSMutableString * filteredString = [[NSMutableString alloc] init];

        int i = 0;
        while (i < [data length]) {

            int expectedLength = 1;

            if      ((buffer[i] & 0b10000000) == 0b00000000) expectedLength = 1;
            else if ((buffer[i] & 0b11100000) == 0b11000000) expectedLength = 2;
            else if ((buffer[i] & 0b11110000) == 0b11100000) expectedLength = 3;
            else if ((buffer[i] & 0b11111000) == 0b11110000) expectedLength = 4;
            else if ((buffer[i] & 0b11111100) == 0b11111000) expectedLength = 5;
            else if ((buffer[i] & 0b11111110) == 0b11111100) expectedLength = 6;

            int length = MIN(expectedLength, [data length] - i);
            NSData * character = [NSData dataWithBytes:&buffer[i] length:(sizeof(Byte) * length)];

            NSString * possibleString = [NSString stringWithUTF8String:[character bytes]];
            if (possibleString) {
                [filteredString appendString:possibleString];
            }
            i = i + expectedLength;
        }
        bufferStr = filteredString;
    }

    return bufferStr;
}
+(NSString*)数据2UTF8String:(NSData*)数据{
//首先尝试进行“标准”UTF-8转换
NSString*bufferStr=[[NSString alloc]initWithData:data
编码:NSUTF8StringEncoding];
//如果失败,请执行“有损”UTF8转换
如果(!bufferStr){
常量字节*缓冲区=[数据字节];
NSMutableString*filteredString=[[NSMutableString alloc]init];
int i=0;
而(i<[数据长度]){
int expectedLength=1;
如果((缓冲区[i]&0b10000000)=0b00000000)expectedLength=1;
如果((缓冲区[i]&0b11100000)=0b11000000)预期长度=2;
如果((缓冲区[i]&0b11110000)=0b11100000)预期长度=3;
如果((缓冲区[i]&0b11111000)=0b11110000)预期长度=4;
如果((缓冲区[i]&0b11111100)=0b11111000)预期长度=5;
如果((缓冲区[i]&0B111110)=0b11111100)预期长度=6;
int length=MIN(预期长度,[数据长度]-i);
NSData*字符=[NSData dataWithBytes:&缓冲区[i]长度:(sizeof(Byte)*长度)];
NSString*possibleString=[NSString stringWithUTF8String:[字符字节];
如果(可能限制){
[filteredString appendString:possibleString];
}
i=i+预期长度;
}
bufferStr=filteredString;
}
返回缓冲区str;
}
如果你有任何意见,请让我知道。
谢谢Larme

可能是这样的:
NSMutableString*finalString=[[NSMutableString alloc]init];while([directoryStream hasBytesAvailable]){len=[directoryStream read:buffer maxLength:sizeof(buffer)];if(len>0){for(int i=0;i
。如果
NSData
NSString
to
有效,是否测试每次/char的想法。正在使用哪种服务器协议?您如何知道流何时实际到达UTF-8字节的末尾?您是否提前知道字节计数,或者在数据末尾是否有某种标记?您不应该是c将UTF-8缓冲区转换为字符串,直到您确定您实际完成了完整的UTF-8缓冲区。如果原始数据在多个
NSStreamEventHasBytesAvailable
事件中进行流式传输并以片段形式传递,则等待
hasBytesAvailable
为假是不够可靠的。获取一个事件,附加该可用数据将数据写入缓冲区,然后在将其转换为字符串之前检查缓冲区是否已到达数据的末尾。根据需要重复此操作。@Larme,这是不可能的。UTF8字符可以由多个字节组成。如果是UTF8,则不能检查每个字节。其他答案,我已经想到了,但我对服务器没有影响。这就是为什么我选择了nt创建一个方法,该方法在字符串包含无效UTF8时也解析该字符串character@Wubbe:根据doc(),您仍然可以检查每个字符,不仅可以使用一个字节,还可以根据需要检查连续uint8的可能值,这是最后一个“字符”在当前流和下一个流之间溢出,当您尝试获取长度超过缓冲区长度的字符时,可能会出现堆栈溢出。因此,请在之前检查i+预期长度(在执行
NSData character
之前)在缓冲区的范围内。如果超过缓冲区长度,您可能还希望在下次调用委托方法时将其保留为缓冲区的开始。您说得对!我相应地更改了代码段。完美的解决方案!非常感谢