2012-05-06 33 views
8

如何使用boost::spirit來匹配utf8 unicode字符?如何將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> 

UPDATE:

好的,我對此有更多的瞭解,下面的代碼是有用的。它首先將輸入轉換成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代碼點的向量?

+0

我發現它可能使用boost正則表達式unicode迭代器,它將utf8輸入轉換爲utf32代碼點(http://comments.gmane.org/gmane.comp.parsers.spirit.general/23490),我試圖弄清楚這是如何工作的...任何幫助表示讚賞。 – Frank

+0

此外,來自命名空間'boost :: spirit :: unicode'的元素在這裏使用(http://boost-spirit.com/dl_more/scheme/scheme_v0.2/sexpr.hpp),但我不知道什麼是Spirit這需要版本。礦井來自boost 1.49,它沒有'boost :: spirit :: unicode'。 – Frank

+0

boost :: spirit:unicode命名空間是在包含任何Boost :: Spirit頭文件之前設置BOOST_SPIRIT_UNICODE變量時定義的: '#define BOOST_SPIRIT_UNICODE' –

回答

5

我還沒有太多的經驗,但顯然Spirit(SVN中繼版本)支持Unicode。

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

參見,例如, sexpr parser sample這是在計劃演示。

BOOST_ROOT/libs/spirit/example/scheme 

相信這是基於由布萊斯Lelbach ,具體展示了從演示文稿的演示:

  • WCHAR支持
  • utree屬性(仍然實驗)
  • s-expressions

有一篇關於S-expressions and variant的在線文章。


如果它確實是,這裏是the video from that presentation,發現here (odp)

+0

添加鏈接和引用 – sehe

+0

謝謝,我已經看到了這個例子(見我的第二條評論上面)。它在Boost 1.49中不可用,但我會查看boost :: spirit的最新SVN版本。 – Frank

+0

(修改後的答案文本顯示它在SVN中繼版本中可用,而不是官方的Boost下載。) – Frank

1

你不能。問題不在於boost :: spirit,而是Unicode is complicatedchar並不意味着一個字符,它意味着一個'字節'。即使你在編碼級別上工作,用戶感知的字符也可以由多個代碼點表示。 (例如,пустынных是9個字符,但是有10個代碼點,可能在俄文中不夠清楚,因爲它沒有廣泛使用變音符號,其他語言都可以)

要實際遍歷用戶感知的字符Unicode術語),您需要使用Unicode專用庫,即ICU。

但是,對字符進行迭代的真實用途是什麼?

+1

我想要構建一個解析器,該正則表達式用一個正則表達式構建AST,字符串輸入。所以我需要解析的可能是這樣的,例如「ʉ* [a-ɧ] +」。只要用'boost :: spirit'工作,我就可以使用ICU。 – Frank

+1

@Frank:但這是無稽之談!在Unicode中什麼意思?和א-я? – ybungalobill

+2

這不是廢話。每個unicode字符都有一個編碼點,例如,'a'具有U + 0061(= 97),並且'具有U + 0267(615)。所以範圍「[a-ɧ]」表示代碼點大於等於97且小於等於615的字符。 – Frank

0

在升壓1.58 slides (pdf),因爲我可以用這個匹配任何Unicode符號:

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

我不知道如何定義一個特定範圍的unicode符號。

相關問題