如何将unicode字符与boost :: spirit匹配?

时间:2012-05-06 21:45:12

标签: c++ parsing boost boost-spirit

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

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

$ 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字符的迭代器(按照建议here):

#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 table的说法,

似乎是正确的。

现在,有人可以告诉我如何打印实际字符,给定这个Unicode代码点向量?

3 个答案:

答案 0 :(得分:7)

我对它没有多少经验,但显然Spirit(SVN trunk版本)支持Unicode。

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

参见,例如计划演示中的 sexpr parser sample

BOOST_ROOT/libs/spirit/example/scheme

我相信这是基于Bryce Lelbach 1 的演示,该演示特别展示:

  • wchar support
  • utree属性(仍然实验性的)
  • s表达式

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


1 如果确实如此,这里是 the video from that presentation ,而slides (pdf)已找到here (odp)

答案 1 :(得分:2)

你做不到。问题不在于boost :: spirit而是Unicode is complicatedchar不代表字符,它意味着'字节'。即使您在代码点级别上工作,用户感知的字符仍然可以由多个代码点表示。 (例如,пустынных是9个字符,但有10个代码点。在俄语中可能不够清楚,因为它没有广泛使用变音符号。其他语言也是如此。)

要实际迭代用户感知的字符(或Unicode术语中的字形集群),您需要使用Unicode专用库,即ICU。

然而,迭代字符的现实用途是什么?

答案 2 :(得分:2)

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

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

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