【问题标题】:Replace invalid XML unicode sequence in a string C++替换字符串 C++ 中的无效 XML unicode 序列
【发布时间】:2018-04-12 04:14:28
【问题描述】:

在 C++ 中寻找与 Java 中的 Character.isIdentifierIgnorable() 对应的函数。基本上我必须用从它们派生的另一个字符串替换它们(这样信息就不会丢失)。

我在 Java 中的实现:

public static String replaceInvalidChar (String s) {
     StringBuffer sb = new StringBuffer();

     char[] characters = s.toCharArray();

     for (char c : characters) {
             if (Character.isIdentifierIgnorable(c)){
                     sb.append(String.format("\\u%04x", (int)c));
             } else {
                     sb.append(c);
             }
     }

     return sb.toString();
}

打算在 C++ 中做同样的事情,但为了替换字符,我需要先检测它们。有人可以帮我吗?

【问题讨论】:

  • 看起来 std::iswctrlstd::iswspace 可能会在将 utf8 转换为 UCS2/UTF16 明智的字符串后覆盖它。

标签: c++ string unicode xml-parsing


【解决方案1】:

据我所知,Character.isIdentifierIgnorable() 的工作原理可能对你有用:

std::wstring replaceInvalidChar(std::wstring const& s)
{
    std::wostringstream sb;

    for(auto c: s)
    {
        if(std::iswcntrl(c) && !std::iswspace(c))
            sb << L"\\u" << std::hex << std::setw(4) << std::setfill(L'0') << int(c);
        else
            sb << wchar_t(c);
    }

    return sb.str();
}

【讨论】:

  • 它错过了“\u0000”,但适用于“\u001b”。知道如何解决这个问题吗?
  • @SauravSahu 您如何初始化包含\u0000 的字符串? (一些构造函数在null字符(\u0000)之前结束字符串。例如,您可以使用std::wstring s{L"hello\u001b \0 \t \n \4d\5y ", 18};
  • 在 Java ideone.com/E5IFPN 中,我可以解析到最后,但不能在 CPP ideone.com/i0ozyo 中解析。
  • @SauravSahu 是的,因为null 字符在用于初始化字符串时会终止该字符串。您需要使用指定其长度的构造函数,如下所示:ideone.com/SYfjHT
  • @SauravSahu 如果您想使用更类似于Java 的语法(但仍然不一样),您可以使用std::wstring 初始化std::wstring,方法是添加s 作为字符串文字和using std::literals 的后缀如下:ideone.com/Ls50Pi
【解决方案2】:

每个 Java 的 Character.isIdentifierIgnorable(char) documentation:

确定指定字符是否应被视为 Java 标识符或 Unicode 标识符中的可忽略字符。

在 Java 标识符或 Unicode 标识符中可以忽略以下 Unicode 字符:

  • 非空白的 ISO 控制字符

    • “\u0000”到“\u0008”
    • “\u000E”到“\u001B”
    • '\u007F' 到 '\u009F'
  • 所有具有 FORMAT 通用类别值的字符

注意:此方法无法处理supplementary characters。要支持所有 Unicode 字符,包括补充字符,请使用 isIdentifierIgnorable(int) 方法

参数
ch - 要测试的字符。

返回
true,如果该字符是一个可忽略的控制字符,它可能是 Java 或 Unicode 标识符的一部分; false 否则。

所以,试试这样的:

#include <string>
#include <sstream>
#include <iomanip>

bool isFormatChar(wchar_t ch)
{
    switch (ch)
    {
        case 0x00AD:

        case 0x2028:
        case 0x2029:

        case 0x061C:
        case 0x200E:
        case 0x200F:
        case 0x202A:
        case 0x202B:
        case 0x202C:
        case 0x202D:
        case 0x202E:
        case 0x2066:
        case 0x2067:
        case 0x2068:
        case 0x2069:

            // and many many more! For the full list of Format chars, see:
            // http://www.fileformat.info/info/unicode/category/Cf/list.htm
            // http://www.fileformat.info/info/unicode/category/Zl/list.htm
            // http://www.fileformat.info/info/unicode/category/Zp/list.htm

            return true;
    }

    return false;
}

std::wstring replaceInvalidChar(const std::wstring &s)
{
    std::wostringstream sb;

    for (auto ch: s)
    {
        if (((ch >= 0x0000) && (ch <= 0x0008)) ||
            ((ch >= 0x000E) && (ch <= 0x001B)) ||
            ((ch >= 0x007F) && (ch <= 0x009F)) ||
            isFormatChar(ch))
        {
            sb << L"\\u" << std::hex << std::nouppercase << std::setw(4) << std::setfill(L'0') << int(ch);
        } 
        else
        {
            sb.put(ch);
        }
    }

    return sb.str();
}

【讨论】:

    猜你喜欢
    • 2016-11-28
    • 2013-06-20
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    相关资源
    最近更新 更多