2012-05-06 8 views
8

¿Cómo puedo unir caracteres utf8 unicode usando boost::spirit?Cómo hacer coincidir caracteres unicode con boost :: spirit?

Por ejemplo, quiero reconocer todos los caracteres de esta cadena:

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

Cuando trato de este sencillo programa boost::spirit que no coincidirá con los caracteres Unicode correctamente:

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

se comporta como esto:

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

ACTUALIZACIÓN:

Bien, trabajé en esto un poco más, y el siguiente código está funcionando. En primer lugar, convierte la entrada en un iterador de caracteres Unicode de 32 bits (como se recomienda 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; 
} 

El código imprime los puntos de código Unicode:

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

que parece ser correcta, de acuerdo con el oficial Unicode table.

Ahora, ¿alguien puede decirme cómo imprimir los caracteres reales, dado este vector de puntos de código Unicode?

+0

Descubrí que es posible utilizar los iteradores Unicode boost regex, que convierten la entrada utf8 en puntos de código utf32 (http://comments.gmane.org/gmane.comp.parsers.spirit.general/23490), y estoy intentando descubrir cómo funciona ... Se agradece cualquier ayuda. – Frank

+0

Además, los elementos del espacio de nombres 'boost :: spirit :: unicode' se usan aquí (http://boost-spirit.com/dl_more/scheme/scheme_v0.2/sexpr.hpp), pero no sé qué Spirit versión que necesita El mío es de boost 1.49, y no tiene 'boost :: spirit :: unicode'. – Frank

+0

El espacio de nombres boost :: spirit: Unicode se define al establecer la variable BOOST_SPIRIT_UNICODE antes de incluir cualquier archivo de encabezado de Boost :: Spirit: '#define BOOST_SPIRIT_UNICODE' –

Respuesta

5

No tengo mucha experiencia con él, pero al parecer Spirit (versión troncal SVN) es compatible con Unicode.

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

See, e.g. sexpr parser sample que se encuentra en la demostración del esquema.

BOOST_ROOT/libs/spirit/example/scheme 

Creo que esto se basa en la demostración de una presentación de Bryce Lelbach , que muestra en concreto:

  • wchar apoyar
  • atributos utree (todavía experimental)
  • s-expresiones

Hay un artículo en línea sobre S-expressions and variant.


En caso de que es, en efecto, aquí es the video from that presentation y la slides (pdf) como se encuentra here (odp)

+0

enlaces y referencias agregados – sehe

+0

Gracias, he visto ese ejemplo (ver mi segundo comentario arriba). No está disponible en Boost 1.49, pero veré la última versión de SVN de boost :: spirit. – Frank

+0

(Texto de respuesta modificado para mostrar que está disponible en la versión troncal de SVN, a diferencia de las descargas oficiales de Boost). – Frank

1

No puede. El problema no está en boost :: spirit sino que Unicode is complicated. char no significa un carácter, significa un 'byte'. E incluso si trabaja en el nivel de punto de código, aún un carácter percibido por el usuario puede estar representado por más de un punto de código. (Por ejemplo, пустынных es de 9 caracteres pero 10 puntos de código. Aunque puede no ser lo suficientemente claro en ruso porque no usa diacríticos extensivamente. otros lenguajes sí lo hacen.)

Para iterar realmente sobre el carácter percibido por el usuario (o clústeres de grafemas en Terminología Unicode), necesitarás usar una biblioteca especializada Unicode, llamada ICU.

Sin embargo, ¿cuál es el uso en el mundo real de iterar sobre los personajes?

+1

Quiero construir un analizador que crea un AST a partir de una expresión regular que se proporciona como entrada de cadena Entonces, lo que necesito analizar puede verse así, por ejemplo, "ʉ * [a-ɧ] +". Estoy bien con el uso de la UCI, siempre y cuando de alguna manera funcione con 'boost :: spirit'. – Frank

+1

@Frank: ¡Pero es una tontería! ¿Qué significará a-in en Unicode? Y א- я? – ybungalobill

+2

No es una tontería. Cada carácter Unicode tiene un punto de código, por ejemplo, 'a' tiene U + 0061 (= 97) y ɧ tiene U + 0267 (615). Entonces, el rango "[a-ɧ]" significa un carácter con un punto de código> = 97 y <= 615. – Frank

0

En Boost 1.58 puedo coincidir con los símbolos Unicode con esto:

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

No sé cómo definir un rango específico de símbolos Unicode.

Cuestiones relacionadas