tokenizer c++ full-text-search tokenize

tokenizer - strtok c++



Tokenizer para texto completo (7)

Bueno, comenzaría buscando Boost y ... hop: Boost.Tokenizer

Lo bueno? Por defecto, se divide en espacios en blanco y puntuación porque es para texto, por lo que no olvidará un símbolo.

De la introducción:

#include<iostream> #include<boost/tokenizer.hpp> #include<string> int main(){ using namespace std; using namespace boost; string s = "This is, a test"; tokenizer<> tok(s); for(tokenizer<>::iterator beg=tok.begin(); beg!=tok.end();++beg){ cout << *beg << "/n"; } } // prints This is a test // notes how the '','' and '' '' were nicely removed

Y hay características adicionales:

  • puede escapar de los personajes
  • es compatible con Iterators así que puedes usarlo directamente con un istream ... y por lo tanto con un ifstream

y algunas opciones (como mantener tokens vacíos, etc.)

¡Echale un vistazo!

Este debería ser un caso ideal de no reinventar la rueda, pero hasta ahora mi búsqueda ha sido en vano.

En lugar de escribir uno, me gustaría usar un tokenizador de C ++ existente. Los tokens se deben utilizar en un índice para la búsqueda de texto completo. El rendimiento es muy importante, analizaré muchos gigabytes de texto.

Editar: tenga en cuenta que los tokens se utilizarán en un índice de búsqueda. Crear tales tokens no es una ciencia exacta (afaik) y requiere algunas heurísticas. Esto se ha hecho mil veces antes, y probablemente de mil maneras diferentes, pero ni siquiera puedo encontrar una de ellas :)

¿Algún buen puntero?

¡Gracias!


Escribí mi propio tokenizador como parte del motor de búsqueda e indexación SWISH++ código abierto.

También está el tokenizer de ICU que maneja Unicode.


La biblioteca del kit de herramientas de cadenas de C ++ (StrTk) tiene la siguiente solución para su problema:

#include <iostream> #include <string> #include <deque> #include "strtk.hpp" int main() { std::deque<std::string> word_list; strtk::for_each_line("data.txt", [&word_list](const std::string& line) { const std::string delimiters = "/t/r/n ,,.;:''/"" "!@#$%^&*_-=+`~///" "()[]{}<>"; strtk::parse(line,delimiters,word_list); }); std::cout << strtk::join(" ",word_list) << std::endl; return 0; }

Más ejemplos se pueden encontrar Here


Podría mirar en std::stringstream desde <sstream> . strtok estilo C tiene una serie de problemas de usabilidad, y las cadenas de estilo C son simplemente problemáticas.

Aquí hay un ejemplo ultra trivial de esto para convertir una oración en palabras:

#include <sstream> #include <iostream> #include <string> int main(void) { std::stringstream sentence("This is a sentence with a bunch of words"); while (sentence) { std::string word; sentence >> word; std::cout << "Got token: " << word << std::endl; } } janks@phoenix:/tmp$ g++ tokenize.cc && ./a.out Got token: This Got token: is Got token: a Got token: sentence Got token: with Got token: a Got token: bunch Got token: of Got token: words Got token:

La clase std::stringstream es "bidireccional", ya que admite entrada y salida. Probablemente querrá hacer solo uno o el otro, por lo que usaría std::istringstream o std::ostringstream .

Lo bello de ellos es que también son std::istream y std::ostream s respectivamente, por lo que puedes usarlos como std::ostream std::cin o std::cout , que esperamos que te resulten familiares.

Algunos podrían argumentar que estas clases son caras de usar; std::strstream from <strstream> es casi lo mismo, pero está construido sobre cadenas más baratas terminadas en 0 de estilo C. Podría ser más rápido para ti. Pero de todos modos, no me preocuparía por el rendimiento de inmediato. Haz que algo funcione, y luego haz un punto de referencia. Lo más probable es que pueda obtener suficiente velocidad simplemente escribiendo C ++ bien escrito que minimice la creación y destrucción innecesarias de objetos. Si aún no es lo suficientemente rápido, entonces puedes buscar en otra parte. Sin embargo, estas clases probablemente son lo suficientemente rápidas. Su CPU puede desperdiciar miles de ciclos en la cantidad de tiempo que lleva leer un bloque de datos de un disco duro o red.


Puede usar Ragel State Machine Compiler para crear un tokenizador (o un analizador léxico).

El código generado no tiene dependencias externas.

Le sugiero que mire la muestra clang.rl para ver un ejemplo relevante de la sintaxis y el uso.


Si el rendimiento es un problema principal, probablemente deberías apegarte a las buenas características antiguas que seguramente serán rápidas:

/* strtok example */ #include <stdio.h> #include <string.h> int main () { char str[] ="- This, a sample string."; char * pch; printf ("Splitting string /"%s/" into tokens:/n",str); pch = strtok (str," ,.-"); while (pch != NULL) { printf ("%s/n",pch); pch = strtok (NULL, " ,.-"); } return 0; }


Una biblioteca de expresiones regulares podría funcionar bien si tus tokens no son demasiado difíciles de analizar.