【问题标题】:in linux using boost xml_parser how to read and compare windows-1251 literals?在 linux 中使用 boost xml_parser 如何读取和比较 windows-1251 文字?
【发布时间】:2026-01-11 18:55:02
【问题描述】:

在 Linux 中我有这样的东西:

boost::property_tree::xml_parser::read_xml(argv[1], pt);
// huge parsing
            for (auto const& itemNode : rootNode2.second) {
                const pt::ptree& dealAttributes = itemNode.second.get_child("<xmlattr>", empty_ptree());
                for (auto const& dealAttr : dealAttributes)
                {
                    const std::string& attrName = dealAttr.first;
                    const std::string& attrVal = dealAttr.second.data();
  • 原始 xml 是 windows-1251。
  • attrVal 是俄罗斯文字
  • 我需要它与程序中的常量进行比较。

我应该如何定义这个常量?在 Linux 中,默认的俄语编码似乎不是 Windows-1251,所以我的比较失败了。

这是一个示例 xml:

<?xml version="1.0" encoding="cp1251"?>
<root>
    <item accounting_currency_code="RUB" board_name="ФБ Т+2"
        broker_commission="71.85" broker_ref="3/00/2"
        conclusion_date="2013-09-11T00:00:00" conclusion_time="2013-09-11T11:04:35"
        deal_no="480" execution_date="2013-09-12T00:00:00" price="144.700000"
        price_currency_code="RUB" request_no="1976"
        security_grn_code="1-02-008-A" security_name="ГАЗПРОМ ао"
        sell_qnty="5000.00000000" volume_currency="718500.00"
        volume_rur="718500.00"/>
</root>

【问题讨论】:

  • 命令 locale -a 将显示您的系统上可用的语言环境,我在 Ubuntu 中对其进行了测试,但我没有 Windows-1251
  • 这里有一个解决方案可以在Ubuntu中添加Windows-1251forum.ubuntu.ru/index.php?topic=220034.0
  • 您有示例 XML 吗?所以我们知道你在说什么并且可以测试?
  • @sehe 我不敢给出示例 xml,因为它包含机密信息。一般来说,我需要调整 boost::property_tree::xml_parser 以获得正确的编码,并使用相同的编码在我的代码中声明文字。
  • 来吧。您可以比我们更容易地获得匿名样本。只是编造一些东西?只要能证明问题...

标签: c++ linux boost


【解决方案1】:

好的,这是我使用“随机样本”“成功”的步骤:

  1. 创建示例输入:

    调用它,例如input.xml 并确保它保存在 cp2151 中:

    <?xml version="1.0" encoding="windows-1251"?>
    <root>
      <deal id="1" silly="е">
            hello
        </deal>
    </root>
    

    那是 U+0435(名称:西里尔小写字母 IE)。

  2. 配置您的系统以支持 cp1251 语言环境

    对我来说,我不得不

    • 编辑 /var/lib/locales/supported.d/local 添加ru_RU.CP1251 CP1251,然后
    • sudo dpkg-reconfigure locales
  3. 灌输!

    使用具有特定语言环境的read_xmlwrite_xml

    使用Boost Locale生成知道字符集转换的locale实例facets

    boost::locale::generator gen;
    auto loc = gen.generate("ru_RU.CP1251");
    
  4. 利润

注意我必须采取特殊的预防措施来验证“debug.xml”文件的内容。我的 vim 错误地检测到了编码,将其显示为 latin1(而不是 "å")。我用过

:ed ++enc=cp1251 debug.xml

强制正确的代码页。

完整演示

Live On Coliru

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/locale.hpp>
#include <boost/locale/generator.hpp>
#include <iostream>
#include <fstream>

using boost::property_tree::ptree;

static ptree const& empty_ptree() {
    static ptree _instance;
    return _instance;
}

int main(int argc, char** argv) {
    assert(argc>1);
    boost::locale::generator gen;
    auto loc = gen.generate("ru_RU.CP1251");

    ptree pt;

    read_xml(argv[1], pt, 0, loc);

    ptree::value_type& rootNode2 = *pt.begin();

    // huge parsing
    for (auto const& itemNode : rootNode2.second) {
        const ptree& dealAttributes = itemNode.second.get_child("<xmlattr>", empty_ptree());
        for (auto const& dealAttr : dealAttributes)
        {
            const std::string& attrName = dealAttr.first;
            const std::string& attrVal  = dealAttr.second.data();

            std::cout << "Attribute '" << attrName << "' hath value "; // '" << attrVal << "'\n";

            int pos = 1;
            for (uint8_t ch : attrVal) // prevent sign-extension
            {
                if (pos++ == 8) {
                    std::cout << '\n';
                    pos = 1;
                }
                std::cout << std::hex << std::setw(2) << std::setfill('0') << std::showbase << static_cast<int>(ch) << " ";
            }
            std::cout << "\n";
        }
    }

    auto settings = boost::property_tree::xml_writer_make_settings<std::string>(' ', 4, "windows-1251");
    //boost::property_tree::xml_parser::write_xml_element(ofs, "root", pt, 0, settings);
    write_xml("debug.xml", pt, loc, settings);
}

它在 Coliru 上运行,包括语言环境支持(赞,Coliru!),并且十六进制转储 debug.xml 以进行验证:

Attribute 'id' hath value 0x31 
Attribute 'silly' hath value 0xe5 
0000000: 3c3f 786d 6c20 7665 7273 696f 6e3d 2231  <?xml version="1
0000010: 2e30 2220 656e 636f 6469 6e67 3d22 7769  .0" encoding="wi
0000020: 6e64 6f77 732d 3132 3531 223f 3e0a 3c72  ndows-1251"?>.<r
0000030: 6f6f 743e 0a20 2020 200d 2623 3130 3b20  oot>.    .&#10; 
0000040: 200d 2623 3130 3b0a 2020 2020 3c64 6561   .&#10;.    <dea
0000050: 6c20 6964 3d22 3122 2073 696c 6c79 3d22  l id="1" silly="
0000060: e522 3e0d 2623 3130 3b20 2020 2020 2020  .">.&#10;       
0000070: 2068 656c 6c6f 0d26 2331 303b 2020 2020   hello.&#10;    
0000080: 3c2f 6465 616c 3e0a 3c2f 726f 6f74 3e0a  </deal>.</root>.

如您所见,0x22 0xe5 0x22 是 cp1251 中 "е" 的正确十六进制表示

【讨论】:

  • 我回答这个问题的录制直播在这里:part #1part #1。 (experiment)。如您所见,我也尝试了您的示例 XML,它运行良好 :)
  • 如果您在某处声明了字符串文字并与 security_name 属性值进行比较?
  • 啊。应该不是问题 IFFFF (!!) 您的源使用 cp1251 编码。最安全的方法是使用例如"\xe5" 在我的例子中。如果您的数据是 UNICODE,则您将进行规范化等。