代码之家  ›  专栏  ›  技术社区  ›  dmkc

NSString initWithData返回null

  •  25
  • dmkc  · 技术社区  · 14 年前

    我正在通过 NSURLConnection NSMutableData connectionDidFinishLoading

    NSString *result = [[NSString alloc] initWithData:data 
                                         encoding:NSUTF8StringEncoding]
    

    结果字符串为空。如果我使用 NSASCIIStringEncoding Content-Type 标题不存在 指定UTF-8编码,但是我已经尝试了许多不同的网站使用类似的场景,并且字符串转换可以很好地进行。似乎这个问题只与给定的web服务有关,但我不知道为什么。

    另一方面,从API中提取web页面和数据是否是一种好的做法,即缓冲数据、转换为字符串,然后再处理字符串?

    非常感谢!

    5 回复  |  直到 14 年前
        1
  •  27
  •   Peter Hosey    14 年前

    你说它肯定是UTF-8,但是如果没有内容类型头,你就不知道这一点(即使你确实有一个标题这样说,它仍然可能是错误的。)

    我的猜测是,您的数据通常是ASCII,它总是正确地解析为UTF-8,但有时您试图解析实际编码为ISO8859-1或Windows代码页1252的数据。这类数据通常是ASCII,但有些字节超出ASCII定义的0127范围。UTF-8期望这样的字节在指定的范围序列内形成一个代码单元序列,但是在其他编码中,任何字节,不管值是多少,都是一个独立的完整字符。尝试将非ASCII非UTF-8数据解释为UTF-8几乎总是会得到错误的结果(错误的字符)或根本没有结果(无法解码;解码器返回 nil ),因为数据一开始从未用UTF-8编码。

        2
  •  9
  •   Vincent Guerci    14 年前

    正如Peter所说,content-type头只是发送内容的“提示”。在服务器端,您可以设置任何内容类型并发送任何字节序列,这可能是无效的。

    Wikipedia about UTF-8 了解这个问题以及如何处理编码错误是值得一读的。

    NSString initWithData:encoding: 当出现解码错误时,严格实现只返回nil(不像java那样使用替换字符)

    (所有UTF-8字符都不正确,仅针对一个拉丁1不稳定字符)

    最好的选择是在服务器端修复,当然,但我不负责这方面。。。

    其原理是使用iconv删除非UTF-8无效字符(即“prt”将变为“prt”)

    iconv -c -f UTF-8 -t UTF-8 invalid.txt > cleaned.txt

    #include "iconv.h"
    
    - (NSData *)cleanUTF8:(NSData *)data {
      iconv_t cd = iconv_open("UTF-8", "UTF-8"); // convert to UTF-8 from UTF-8
      int one = 1;
      iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, &one); // discard invalid characters
    
      size_t inbytesleft, outbytesleft;
      inbytesleft = outbytesleft = data.length;
      char *inbuf  = (char *)data.bytes;
      char *outbuf = malloc(sizeof(char) * data.length);
      char *outptr = outbuf;
      if (iconv(cd, &inbuf, &inbytesleft, &outptr, &outbytesleft)
          == (size_t)-1) {
        NSLog(@"this should not happen, seriously");
        return nil;
      }
      NSData *result = [NSData dataWithBytes:outbuf length:data.length - outbytesleft];
      iconv_close(cd);
      free(outbuf);
      return result;
    }
    

    那么结果呢 NSData 可以使用 NSUTF8StringEncoding

    iconvctl(cd, ICONV_SET_FALLBACKS, &fallbacks);
    

    通过对unicode错误使用回退,可以使用替换字符或更好的字符来尝试其他编码。

        3
  •  5
  •   JeremyP    14 年前

        4
  •  3
  •   Yuji    14 年前

    数据可能是另一种unicode编码,比如UTF16,或者是完全不同的编码。

    有些库可以猜测数据中使用的编码,但这应该是最后的手段。 如果您使用的是web服务,那么该web服务应该有一个说明它使用哪种编码的文档。查找它,或者询问web服务的提供者它使用哪种编码。如果两者都不可用,则应尝试获取样本数据并确定其编码,然后在程序中使用该编码。

    另一方面,从API中提取web页面和数据是否是一种好的做法,即缓冲数据、转换为字符串,然后再处理字符串?

        5
  •  0
  •   Monolo    13 年前

    等一下,操作程序首先是从网上读取的,对吗?为什么不使用NSString stringWithContentsOfURL:usedEncoding:error:

    + (id)stringWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error