如何将字符/字符串进行UTF-8编码

6
我正在使用Twitter API库将状态发布到Twitter。Twitter要求帖子采用UTF-8编码。该库包含一个函数,可以对标准字符串进行URL编码,适用于所有特殊字符(如!@#$%^& *()),但对于重音字符(和其他UTF-8字符)来说,这不是正确的编码方式。
例如,“é”被转换为“%E9”,而不是“%C3%A9”(它基本上只转换为十六进制值)。是否有内置函数可以输入类似“é”的内容并返回类似“%C9%A9”的内容?
编辑:我对UTF-8相当新,如果我请求的内容没有意义,请见谅。
编辑:如果我有一个

string foo = "bar é";

我想要将其转换为。
"bar %C3%A9"

谢谢


3
我认为你想要对字符串进行URL编码,而不是UTF-8编码它。 - Nemanja Trifunovic
@NemanjaTrifunovic:他需要两个东西:“Twitter要求...UTF-8”,而且他正在通过URL传递该值。 - Fred Nurk
2个回答

7

如果你有一个宽字符字符串,你可以使用标准的wcstombs()函数将其编码为UTF8格式。如果你将其编码为其他编码(例如Latin-1),则需要先解码为宽字符串。

Edit: ... 但是wcstombs()函数取决于你的区域设置,并且看起来在Windows上不能选择UTF8区域设置。(你没有说你在使用哪个操作系统。)在Windows上,WideCharToMultiByte()可能更有用,因为��可以在调用中指定编码。


这个函数似乎只是返回与C风格字符串相同的字符串,"é"保持不变而不是被转换为"%C3%A9"。 - tom
不,我是:S -- wcstombs将转换为您配置的区域设置编码,对我来说看起来像是Latin-1,所以这样不好。如果您使用的是Windows,可以尝试使用WideCharToMultiByte()代替。(答案已更新。) - Martin Stone

6
为了理解需要做什么,首先需要了解一些背景知识。不同的编码使用不同的值表示“相同”的字符。例如,Latin-1表示“é”是一个具有值E9(十六进制)的单字节,而UTF-8表示“é”是两个字节序列C3 A9,而UTF-16则表示相同的字符是单个双字节值00E9,而不是像UTF-8那样的两个8位值。(Unicode并不是一种编码,实际上使用与Latin-1相同的代码点值U+E9。)
要从一种编码转换为另一种编码,必须首先将编码值解码为与源编码无关的值(即Unicode代码点),然后在目标编码中重新编码它。如果目标编码不支持源编码的所有代码点,则需要翻译或以其他方式处理此条件。
这个重新编码步骤需要知道源编码和目标编码。
您的API函数没有进行编码转换;它似乎是对任意字节字符串进行URL转义。函数的作者显然假设您已经转换为UTF-8。
为了转换为UTF-8,您必须知道您的系统使用的编码,并能够映射到Unicode代码点。从那里,UTF-8编码就很简单了。
根据您的系统,这可能只需将“本地”字符集(对于您来说,“é”为E9,因此可能是Windows-1252、Latin-1或非常相似的东西)转换为宽字符(如果sizeof(wchar_t)为2,则可能是UTF-16或UCS-2,如果sizeof(wchar_t)为4,则可能是UTF-32),然后再转换为UTF-8。如Martin所回答的那样,wcstombs可以处理这个转换的第二部分,但这取决于系统。但是,我认为Latin-1是Unicode的一个子集,因此从此源编码进行转换可以跳过宽字符步骤。Windows-1252接近于Latin-1,但用可打印字符替换了一些控制字符。

我之前没有提到,但是一旦你转换为UTF-8,你仍然需要调用这个API函数来对值进行URL转义。 - Fred Nurk
很好的解释。我感觉我的编码理解受益于此(从来不是编码的粉丝)。谢谢! - Anthony Atkinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接