2012-05-06 13 views
8

Jak mogę dopasować znaki Unicode Utf8 przy użyciu boost::spirit?Jak dopasować znaki Unicode do boost :: spirit?

Na przykład, chcę rozpoznać wszystkich znaków w tym ciągu:

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

Kiedy próbuję to proste boost::spirit programu nie będzie pasować do znaków Unicode poprawnie:

#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; 
} 

zachowuje się jak to:

$ 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> 

AKTUALIZACJA:

OK, trochę nad tym pracowałem, a poniższy kod działa. Najpierw przekształca wejściowej do iteracyjnej 32-bitowych znaków UNICODE (jak zaleca 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; 
} 

Kod drukuje unikodowym punkty kodowe:

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

, który wydaje się być prawidłowa, według oficjalny Unicode table.

Teraz, czy ktoś może mi powiedzieć, jak wydrukować rzeczywiste znaki zamiast tego wektora punktów kodu Unicode?

+0

Znalazłem, że może to być możliwe za pomocą doładowania unerode regex, które przekształcają dane wejściowe utf8 na punkty kodowe utf32 (http://comments.gmane.org/gmane.comp.parsers.spirit.general/23490), i próbuję dowiedzieć się, jak to działa ... Każda pomoc jest doceniana. – Frank

+0

Stosowane są również elementy z przestrzeni nazw 'boost :: spirit :: unicode' (http://boost-spirit.com/dl_more/scheme/scheme_v0.2/sexpr.hpp), ale nie wiem, co to jest Spirit Wersja tego potrzebuje. Mój jest z boostu 1.49, i nie ma 'boost :: spirit :: unicode'. – Frank

+0

Przypisanie :: spirit: unicode jest zdefiniowane podczas ustawiania zmiennej BOOST_SPIRIT_UNICODE przed dodaniem dowolnego pliku nagłówkowego Boost :: Spirit: '#define BOOST_SPIRIT_UNICODE' –

Odpowiedz

5

Nie mam zbyt dużego doświadczenia z nim, ale najwyraźniej Spirit (wersja SVN trunk) obsługuje Unicode.

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

Zobacz np. the która jest w schemacie demonstracyjnym.

BOOST_ROOT/libs/spirit/example/scheme 

Wierzę, że ta jest oparta na demo z prezentacji Bryce Lelbach , która wyraźnie prezentuje:

  • wchar wspierania
  • atrybuty utree (nadal doświadczalnie)
  • s-wyrażenia

Istnieje artykuł online na temat S-expressions and variant.


W przypadku, gdy jest rzeczywiście, jest tu the video from that presentation i slides (pdf) jak stwierdzono here (odp)

+0

dodane linki i referencje – sehe

+0

Dzięki, widziałem ten przykład (patrz mój drugi komentarz powyżej). Nie jest dostępny w Boost 1.49, ale sprawdzę najnowszą wersję boost :: spirit dla SVN. – Frank

+0

(Zmodyfikowano tekst odpowiedzi, aby pokazać, że jest dostępny w wersji trunkingowej SVN, w przeciwieństwie do oficjalnych pobrań pobrania). – Frank

1

Nie możesz. Problem nie polega na pobudzeniu :: ducha, ale na tym, że Unicode is complicated. char nie oznacza postaci, to "bajt". Nawet jeśli pracujesz na poziomie współrzędnych, nadal postrzegana postać może być reprezentowana przez więcej niż jeden kod. (Np пустынных ma 9 znaków, ale 10 codepoints. To może nie być wystarczająco jasne po rosyjsku, choć ponieważ nie używać znaków diakrytycznych obszernie. Inne języki robić.)

Aby rzeczywiście iteracyjne nad użytkownika postrzeganego charakteru (lub w klastrach grafem Terminologia Unicode), będziesz potrzebować biblioteki specjalistycznej Unicode, a konkretnie ICU.

Jakie jest jednak rzeczywiste użycie iteracji znaków?

+1

Chcę zbudować analizator składniowy, który buduje AST z wyrażenia regularnego, które jest dostarczane jako wejście łańcuchowe. To, co muszę analizować, może wyglądać tak, na przykład "ʉ * [a-ɧ] +". Nie mam problemu z używaniem ICU, o ile w jakiś sposób działa z 'boost :: spirit'. – Frank

+1

@Frank: Ale to nonsens! Co a-ɧ będzie oznaczać w Unicode? I א- я? – ybungalobill

+2

To nie jest bzdura. Każdy znak Unicode ma punkt kodowy, np. "A" ma U + 0061 (= 97), a ɧ ma U + 0267 (615). Zatem zakres "[a-ɧ]" oznacza znak o punkcie kodowym> = 97 i <= 615. – Frank

0

W Boost, 1,58 I można dopasować do dowolnego symbole zakodowanych w z tym:

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

Nie wiem, jak zdefiniować określony zakres symboli Unicode.

Powiązane problemy