如何在 C 中使用 unicode 正确解码 url
How to properly decode url with unicode in C
从我的引荐来源日志中,我正在尝试解码引荐来源,但看起来 %81
和 %8A
不是有效的百分比编码,所以我得到 ri�0�9o
。
我需要通过 websocket 发送解码后的字符串,现在我在浏览器端得到 Could not decode a text frame as UTF-8.
。
这些甚至是有效的百分比编码吗?我怎么知道它们是否有效?
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
void urldecode2(char *dst, const char *src) {
char a, b;
while(*src) {
if((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) {
if(a >= 'a')
a -= 'a'-'A';
if(a >= 'A')
a -= ('A' - 10);
else
a -= '0';
if(b >= 'a')
b -= 'a'-'A';
if(b >= 'A')
b -= ('A' - 10);
else
b -= '0';
*dst++ = 16*a+b;
src+=3;
} else if(*src == '+') {
*dst++ = ' ';
src++;
} else {
*dst++ = *src++;
}
}
*dst++ = '[=11=]';
}
int main () {
const char *in = "http://www.google.co.in/search?q=cari%810%8A9o";
char out[100];
urldecode2(out, in);
printf("%s\n", out);
return 0;
}
%81
和 %8A
是完全有效的 %-escapes,但结果不是 UTF-8 字符串。 URL不要求必须是 UTF-8 字符串,但如今它们通常是。
在我看来,似乎发生了一些非常奇怪的双重编码。我不知道哪个约定使用 three-digit %-编码,但这就是你在 URL 中的样子。假设意图是编码西班牙语单词 "cariño"(care,affection,fondness),它应该是 UTF-8 中的 cari%C3%B1o
,或者 [=29= 中的 cari%F1o
](通常意外出现在 URL 秒)。
有效 UTF-8 序列的规则非常简单,您可以使用正则表达式检查有效序列。并非所有有效序列都映射到字符,其中 66 个被显式映射为 "not characters",但所有有效序列都应被符合标准的解码器接受,即使它后来拒绝解码的字符在语义上不正确。
UTF-8 序列是 one-to-four 字节序列,对应于以下模式之一:(取自 Unicode 标准,table 3.7)
Byte 1 Byte 2 Byte 3 Byte 4
------ ------ ------ ------
00..7F -- -- --
C2..DF 80..BF -- --
E0 A0..BF 80..BF --
E1..EC 80..BF 80..BF --
ED 80..9F 80..BF --
EE..EF 80..BF 80..BF --
F0 90..BF 80..BF 80..BF
F1..F3 80..BF 80..BF 80..BF
F4 80..8F 80..BF 80..BF
任何其他都是非法的。 (因此代码 C0、C1 和 F5 到 FF 根本不会出现。)特别是,十六进制代码 81 和 8A 永远不能开始 UTF-8 序列。
由于没有好的方法可以知道无效序列可能意味着什么,最简单的方法就是将它们去掉。
从我的引荐来源日志中,我正在尝试解码引荐来源,但看起来 %81
和 %8A
不是有效的百分比编码,所以我得到 ri�0�9o
。
我需要通过 websocket 发送解码后的字符串,现在我在浏览器端得到 Could not decode a text frame as UTF-8.
。
这些甚至是有效的百分比编码吗?我怎么知道它们是否有效?
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
void urldecode2(char *dst, const char *src) {
char a, b;
while(*src) {
if((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) {
if(a >= 'a')
a -= 'a'-'A';
if(a >= 'A')
a -= ('A' - 10);
else
a -= '0';
if(b >= 'a')
b -= 'a'-'A';
if(b >= 'A')
b -= ('A' - 10);
else
b -= '0';
*dst++ = 16*a+b;
src+=3;
} else if(*src == '+') {
*dst++ = ' ';
src++;
} else {
*dst++ = *src++;
}
}
*dst++ = '[=11=]';
}
int main () {
const char *in = "http://www.google.co.in/search?q=cari%810%8A9o";
char out[100];
urldecode2(out, in);
printf("%s\n", out);
return 0;
}
%81
和 %8A
是完全有效的 %-escapes,但结果不是 UTF-8 字符串。 URL不要求必须是 UTF-8 字符串,但如今它们通常是。
在我看来,似乎发生了一些非常奇怪的双重编码。我不知道哪个约定使用 three-digit %-编码,但这就是你在 URL 中的样子。假设意图是编码西班牙语单词 "cariño"(care,affection,fondness),它应该是 UTF-8 中的 cari%C3%B1o
,或者 [=29= 中的 cari%F1o
](通常意外出现在 URL 秒)。
有效 UTF-8 序列的规则非常简单,您可以使用正则表达式检查有效序列。并非所有有效序列都映射到字符,其中 66 个被显式映射为 "not characters",但所有有效序列都应被符合标准的解码器接受,即使它后来拒绝解码的字符在语义上不正确。
UTF-8 序列是 one-to-four 字节序列,对应于以下模式之一:(取自 Unicode 标准,table 3.7)
Byte 1 Byte 2 Byte 3 Byte 4
------ ------ ------ ------
00..7F -- -- --
C2..DF 80..BF -- --
E0 A0..BF 80..BF --
E1..EC 80..BF 80..BF --
ED 80..9F 80..BF --
EE..EF 80..BF 80..BF --
F0 90..BF 80..BF 80..BF
F1..F3 80..BF 80..BF 80..BF
F4 80..8F 80..BF 80..BF
任何其他都是非法的。 (因此代码 C0、C1 和 F5 到 FF 根本不会出现。)特别是,十六进制代码 81 和 8A 永远不能开始 UTF-8 序列。
由于没有好的方法可以知道无效序列可能意味着什么,最简单的方法就是将它们去掉。