10

如何使用匹配 utf8 unicode 字符boost::spirit

例如,我想识别此字符串中的所有字符:

$ echo "На берегу пустынных волн" | ./a.out
Н а б е р е гу п у с т ы н н ы х в о л н

当我尝试这个简单boost::spirit的程序时,它不会正确匹配 unicode 字符:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/foreach.hpp>
namespace qi = boost::spirit::qi;

int main() {
  std::cin.unsetf(std::ios::skipws);
  boost::spirit::istream_iterator begin(std::cin);
  boost::spirit::istream_iterator end;

  std::vector<char> letters;
  bool result = qi::phrase_parse(
      begin, end,  // input     
      +qi::char_,  // match every character
      qi::space,   // skip whitespace 
      letters);    // result    

  BOOST_FOREACH(char letter, letters) {
    std::cout << letter << " ";
  }
  std::cout << std::endl;
}

它的行为如下:

$ echo "На берегу пустынных волн" | ./a.out | less
<D0> <9D> <D0> <B0> <D0> <B1> <D0> <B5> <D1> <80> <D0> <B5> <D0> <B3> <D1> <83> <D0> <BF> <D1> <83> <D1> <81> <D1> <82> <D1> <8B> <D0> <BD> <D0> <BD> <D1> <8B> <D1> <85> <D0> 
<B2> <D0> <BE> <D0> <BB> <D0> <BD> 

更新:

好的,我在这方面做了更多工作,下面的代码有点工作。它首先将输入转换为 32 位 unicode 字符的迭代器(如此推荐):

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/foreach.hpp>
#include <boost/regex/pending/unicode_iterator.hpp>
namespace qi = boost::spirit::qi;

int main() {
  std::string str = "На берегу пустынных волн";
  boost::u8_to_u32_iterator<std::string::const_iterator>
      begin(str.begin()), end(str.end());
  typedef boost::uint32_t uchar; // a unicode code point
  std::vector<uchar> letters;
  bool result = qi::phrase_parse(
      begin, end,             // input
      +qi::standard_wide::char_,  // match every character
      qi::space,              // skip whitespace
      letters);               // result
  BOOST_FOREACH(uchar letter, letters) {
    std::cout << letter << " ";
  }
  std::cout << std::endl;
}

该代码打印 Unicode 代码点:

$ ./a.out 
1053 1072 1073 1077 1088 1077 1075 1091 1087 1091 1089 1090 1099 1085 1085 1099 1093 1074 1086 1083 1085 

根据官方Unicode 表,这似乎是正确的。

现在,鉴于此 Unicode 代码点向量,谁能告诉我如何打印实际字符?

4

3 回答 3

7

我没有太多经验,但显然 Spirit(SVN 主干版本)支持 Unicode。

#define BOOST_SPIRIT_UNICODE // We'll use unicode (UTF8) all throughout

例如,参见方案演示中的sexpr 解析器示例。

BOOST_ROOT/libs/spirit/example/scheme

我相信这是基于 Bryce Lelbach 1的演示文稿中的演示,其中特别展示了:

  • wchar 支持
  • utree 属性(仍处于试验阶段)
  • s-表达式

有一篇关于S-expressions 和 variant的在线文章。


1如果确实如此,这里是该演示文稿中的视频幻灯片 (pdf),可在此处找到 (odp)

于 2012-05-07T07:31:46.727 回答
2

你不能。问题不在于 boost::spirit 而是Unicode 很复杂char不是一个字符,而是一个“字节”。即使您在代码点级别工作,用户感知的字符仍然可能由多个代码点表示。(例如 пусты́нных 是 9 个字符,但有 10 个代码点。在俄语中可能不够清楚,因为它没有广泛使用变音符号。其他语言可以。)

要真正迭代用户感知的字符(或 Unicode 术语中的字素簇),您需要使用 Unicode 专用库,即 ICU。

但是,迭代字符的实际用途是什么?

于 2012-05-06T22:14:23.820 回答
2

在 Boost 1.58 中,我可以匹配任何 unicode 符号:

*boost::spirit::qi::unicode::char_

我不知道如何定义特定范围的 unicode 符号。

于 2016-10-06T20:23:16.227 回答