我目前正在努力避免在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”但我必须遗漏一些明显的东西。
不知怎的,我无法理解它。 任何指针都会很棒。
答案 0 :(得分: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,我们看到'1'的终止'0'表示将使用多少字节 - 在这种情况下,2。剥离最初的110
元数据,我们从第一个字节开始留下00011
:表示实际值的最左边的位。
对于下一个字节(1010 1001
),再次从RFC我们看到,对于每个后续字节,10
将是实际值的“前缀”元数据。剥离它,我们留下了101001
。
连接实际值位,我们最终得到00011 101001
,基数为10 233
,基数为16为E9
。
编码识别
从UTF-16值(%FF%FE%E9%00
)中特别考虑的另一件事来自最初的RFC,它提到在编码值本身中没有使用的编码的明确定义。因此,在这种情况下,iOS是“作弊”,为您提供使用何种编码的指示。 FF FE
是UTF-16编码文件中使用的众所周知的字节排序标记,表示UTF-16是使用的编码。至于E9 00
,如上所述,UTF-16总是使用两个字节。在这种情况下,由于它的所有数据都可以用1个字节表示,另一个数据只是空。