0

我目前正在努力解决 iOS 上特殊字符的百分比转义问题,例如查询参数值中包含的“é”。

我正在使用 AFNetworking,但问题并非特定于它。

“é”字符应该被百分比转义为“%E9”,但结果是“%C3%A9”。原因是“é”在 UTF8 中表示为这 2 个字节。

实际的百分比转义方法是众所周知的方法,我将 UTF8 作为字符串编码传递。字符串本身是@"é"。

static NSString * AFPercentEscapedQueryStringPairMemberFromStringWithEncoding(NSString *string, NSStringEncoding encoding) 
{
    static NSString * const kAFCharactersToBeEscaped = @":/?&=;+!@#$()~";
    static NSString * const kAFCharactersToLeaveUnescaped = @"[].";

    return (__bridge_transfer  NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kAFCharactersToLeaveUnescaped, (__bridge CFStringRef)kAFCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(encoding));
}

我曾希望传入 UTF16 字符串编码可以解决它,但事实并非如此。在这种情况下,结果是“%FF%FE%E9%00”,它包含“%E9”,但我必须遗漏一些明显的东西。

不知怎的,我无法理解它。任何指针都会很棒。

4

1 回答 1

1

RFC 3986解释说,除非您正在编码的字符属于未保留的 US-ASCII 范围,否则约定是将字符转换为(在本例中为 UTF8 编码的)字节值,并将该值用作百分比编码基础。

你看到的行为是正确的。

为 UTF-8 与 UTF-16 给出的编码值之间的差异是由几个因素造成的。

编码差异

首先,实际定义各个编码的方式有所不同。UTF-16 将始终使用两个字节来表示其字符,并且本质上将高位字节与低位字节连接以定义代码。(这些字节的顺序将取决于代码是编码为 Little Endian 还是 Big Endian。)另一方面,UTF-8 使用动态数量的字节,这取决于字符在 Unicode 代码页中的位置。UTF-8 关联它将使用多少字节的方式是通过在第一个字节本身中设置的位。

因此,如果我们查看 C3 A9,则可以转换为以下位:

1100 0011 1010 1001

查看RFC 2279,我们看到以 '0' 结尾的 '1' 的开始集合表示将使用多少字节 - 在这种情况下,2. 剥离初始110元数据,我们00011从第一个字节开始: 表示实际值的最左边的位。

对于下一个字节 ( 1010 1001),我们再次从 RFC 中看到,对于每个后续字节,10将是实际值的“前缀”元数据。去掉它,我们就剩下101001.

连接实际值位,我们最终得到00011 101001,它233以 10 为底,或E9以 16 为底。

编码识别

UTF-16 值 ( ) 中要特别考虑的另一件事%FF%FE%E9%00来自原始 RFC,其中提到在编码值本身中没有明确定义所使用的编码。所以在这种情况下,iOS 是在“作弊”,告诉你使用的是什么编码。 FF FE是 UTF-16 编码文件中使用的众所周知的字节排序标记,表示 UTF-16 是使用的编码。至于E9 00,如前所述,UTF-16 总是使用两个字节。在这种情况下,由于它的所有数据都可以用 1 个字节表示,因此另一个只是空的。

于 2012-11-14T15:00:17.397 回答