8

我不知道如何解决:

想象一下,我们有 4 个网站:

  • 答:UTF-8
  • B:ISO-8859-1
  • C: ASCII
  • D:UTF-16

我用 C++ 编写的程序执行以下操作:它下载一个网站并对其进行解析。但它必须了解内容。我的问题不是使用 ASCII 字符完成的解析,例如">"or"<" )完成的解析。

问题是程序应该从网站的文本中找到所有单词。单词是字母数字字符的任意组合。然后我将这些词发送到服务器。数据库和 Web 前端使用 UTF-8。所以我的问题是:

  • 如何将“任何”(或最常用的)字符编码转换为 UTF-8?
  • 如何在 C++ 中使用 UTF-8 字符串?我认为wchar_t不起作用,因为它有 2 个字节长。UTF-8 中的代码点最长为 4 个字节...
  • 对于这样的 UTF-8 字符串,是否有类似isspace(), isalnum(), strlen(),的函数?tolower()

请注意:我不做任何输出(比如std::coutC++ 中做任何输出(如 )。只需过滤掉单词并将它们发送到服务器。

我知道 UTF8-CPP 但它没有is*()功能。正如我所读到的,它不会从其他字符编码转换为 UTF-8。仅从 UTF-* 到 UTF-8。

编辑:我忘了说,程序必须是可移植的:Windows、Linux、...

4

4 回答 4

10

如何将“任何”(或最常用的)字符编码转换为 UTF-8?

ICU(Unicode 的国际组件)是这里的解决方案。它通常被认为是 Unicode 支持的最后发言权。就 Unicode 而言,甚至 Boost.Locale 和 Boost.Regex 也使用它。请参阅我对 Dory Zidon 的回答关于为什么我建议直接使用 ICU 而不是包装器(如 Boost)的评论。

您为给定的编码创建转换器...

#include <ucnv.h>

UConverter * converter;
UErrorCode err = U_ZERO_ERROR;
converter = ucnv_open( "8859-1", &err );
if ( U_SUCCESS( error ) )
{
    // ...
    ucnv_close( converter );
}

...然后使用UnicodeString类作为适当的。

我认为 wchar_t 不起作用,因为它有 2 个字节长。

的大小wchar_t是实现定义的。AFAICR,Windows 是 2 字节(UCS-2 / UTF-16,取决于 Windows 版本),Linux 是 4 字节(UTF-32)。无论如何,由于标准没有为 Unicode定义语义wchar_t,因此使用它是不可移植的猜测。不要猜测,使用ICU。

此类 UTF-8 字符串是否有 isspace()、isalnum()、strlen()、tolower() 等函数?

不是在他们的 UTF-8 编码中,但无论如何你都不会在内部使用它。UTF-8 适合外部表示,但内部 UTF-16 或 UTF-32 是更好的选择。对于 Unicode 代码点(即 UChar32),确实存在上述函数;参考。uchar.h _

请注意:我不在 C++ 中做任何输出(如 std::cout)。只需过滤掉单词并将它们发送到服务器。

检查BreakIterator

编辑:我忘了说,程序必须是可移植的:Windows、Linux、...

如果我还没有说过,使用 ICU,并为自己省去很多麻烦。即使乍一看似乎有点重量级,但它目前最好的实现,它非常便携(我自己在 Windows、Linux 和 AIX 上使用它),您在项目中一次又一次地使用它来来吧,所以花时间学习它的 API 并没有浪费。

于 2013-04-25T07:42:11.067 回答
3

不确定这是否会为您提供所需的一切,但它可能会有所帮助。您是否尝试过查看:

1) Boost.Locale 库?Boost.Locale 在 Boost 1.48(2011 年 11 月 15 日)中发布,使其更容易在 UTF8/16 之间进行转换

以下是文档中的一些方便示例:

string utf8_string = to_utf<char>(latin1_string,"Latin1");
wstring wide_string = to_utf<wchar_t>(latin1_string,"Latin1");
string latin1_string = from_utf(wide_string,"Latin1");
string utf8_string2 = utf_to_utf<char>(wide_string);

2) 还是转换是 C++11 的一部分?

#include <codecvt>
#include <locale>
#include <string>
#include <cassert>

int main() {
  std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
  std::string utf8 = convert.to_bytes(0x5e9);
  assert(utf8.length() == 2);
  assert(utf8[0] == '\xD7');
  assert(utf8[1] == '\xA9');
}
于 2013-04-25T07:13:03.383 回答
1

如何在 C++ 中使用 UTF-8 字符串?我认为 wchar_t 不起作用,因为它有 2 个字节长。UTF-8 中的代码点最长为 4 个字节...

这很简单,有一个名为  tinyutf8的项目  ,它是/的替代品。std::stringstd::wstring

然后用户可以优雅地对codepoints进行操作,而它们的表示总是以chars 编码。


如何将“任何”(或最常用的)字符编码转换为 UTF-8?

您可能想查看(C++11)中std::codecvt_utf8类似模板<codecvt>

于 2016-11-30T15:09:53.557 回答
0

UTF-8 是一种利用第 8 位对非 ASCII(7 位代码)使用多个字节的编码。因此,您不会在多字节序列中找到'\', 。'/'并且isdigit有效(尽管不是阿拉伯语和其他数字)。

它是 ASCII 的超集,可以容纳所有 Unicode 字符,因此绝对要与 char 和 string 一起使用。

检查 HTTP 标头(不区分大小写);它们在 ISO-8859-1 中,在空行之前,然后是 HTML 内容。

Content-Type: text/html; charset=UTF-8

如果不存在,也可能存在

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">      <!-- HTML5 -->

ISO-8859-1 是拉丁语 1,您最好从 Windows-1252 转换,Windows 拉丁语 1 扩展使用 0x80 - 0xBF 用于逗号引号等一些特殊字符。尽管指定了 ISO-8859-1,但即使 MacOS 上的浏览​​器也能理解这些。

转换库:@syam 已经提到。

转换

我们不考虑 UTF-16。可以读取标题并开始直到字符集的元语句作为单字节字符。

从单字节编码到 UTF-8 的转换可以通过表格进行。例如用 Java 生成的:aconst char* table[]由 char 索引。

table[157] = "\xEF\xBF\xBD";


public static void main(String[] args) {
    final String SOURCE_ENCODING = "windows-1252";
    byte[] sourceBytes = new byte[1];
    System.out.println("    const char* table[] = {");
    for (int c = 0; c < 256; ++c) {
        String comment = "";
        System.out.printf("       /* %3d */ \"", c);
        if (32 <= c && c < 127) {
            // Pure ASCII
            if (c == '\"' || c == '\\')
                System.out.print("\\");
            System.out.print((char)c);
        } else {
            if (c == 0) {
                comment = " // Unusable";
            }
            sourceBytes[0] = (byte)c;
            try {
                byte[] targetBytes = new String(sourceBytes, SOURCE_ENCODING).getBytes("UTF-8");
                for (int j = 0; j < targetBytes.length; ++j) {
                    int b = targetBytes[j] & 0xFF;
                    System.out.printf("\\x%02X", b);
                }
            } catch (UnsupportedEncodingException ex) {
                comment = " // " + ex.getMessage().replaceAll("\\s+", " "); // No newlines.
            }
        }
        System.out.print("\"");
        if (c < 255) {
            System.out.print(",");
        }
        System.out.println();
    }
    System.out.println("    };");
}
于 2013-04-25T07:07:49.847 回答