Подтвердить что ты не робот

Tokenizer для полнотекстового

Это должен быть идеальный случай не изобретать колесо, но до сих пор мой поиск был тщетным.

Вместо того, чтобы писать сам, я хотел бы использовать существующий токенизатор С++. Токены должны использоваться в индексе полнотекстового поиска. Производительность очень важна, я буду разбирать много гигабайт текста.

Изменить: обратите внимание, что маркеры должны использоваться в индексе поиска. Создание таких токенов не является точной наукой (afaik) и требует некоторой эвристики. Это было сделано тысячу раз раньше и, вероятно, тысячами разных способов, но я даже не могу найти их:)

Любые хорошие указатели?

Спасибо!

4b9b3361

Ответ 1

Я написал свой собственный токенизатор как часть открытого исходного кода SWISH ++ индексирование и поисковая система.

Также существует токен-генератор ICU который обрабатывает Unicode.

Ответ 2

С++ String Toolkit Library (StrTk) имеет следующее решение вашей проблемы:

#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 ,,.;:'\""
                                                          "[email protected]#$%^&*_-=+`~/\\"
                                                          "()[]{}<>";
                           strtk::parse(line,delimiters,word_list);
                        });

   std::cout << strtk::join(" ",word_list) << std::endl;

   return 0;
}

Дополнительные примеры можно найти здесь

Ответ 3

Если производительность является основной проблемой, вы должны, вероятно, придерживаться старой доброй strtok, которая обязательно будет быстрой:

/* 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;
}

Ответ 4

Библиотека регулярных выражений может работать хорошо, если ваши токены не слишком сложны для анализа.

Ответ 5

Я мог бы заглянуть в std::stringstream из <sstream>. C-style strtok имеет ряд проблем с удобством использования, а строки в стиле C просто хлопотны.

Здесь ультра-тривиальный пример того, как он выражает предложение в словах:

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

[email protected]:/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:

Класс std::stringstream является "двунаправленным", поскольку он поддерживает ввод и вывод. Вы, вероятно, захотите сделать только один или другой, так что вы бы использовали std::istringstream или std::ostringstream.

Красота их в том, что они также std::istream и std::ostream соответственно, поэтому вы можете использовать их, как вы бы использовали std::cin или std::cout, которые, как мы надеемся, вам знакомы.

Некоторые могут утверждать, что эти классы дороги для использования; std::strstream из <strstream> - это в основном одно и то же, но построено поверх более дешевых строк с 0-концевыми строками C-стиля. Это может быть быстрее для вас. Но в любом случае, я бы не стал беспокоиться о производительности сразу. Получите что-то работающее, а затем сравните его. Скорее всего, вы можете получить достаточную скорость, просто написав хорошо написанный С++, который минимизирует ненужное создание и уничтожение объектов. Если это еще не достаточно быстро, вы можете посмотреть в другом месте. Тем не менее, эти классы, вероятно, достаточно быстры. Ваш процессор может тратить тысячи циклов на время, затрачиваемое на чтение блока данных с жесткого диска или сети.

Ответ 6

Вы можете использовать Ragel State Machine Compiler для создания токенизатора (или лексического анализатора).

Сгенерированный код не имеет внешних зависимостей.

Я предлагаю вам посмотреть пример clang.rl для соответствующего примера синтаксиса и использования.

Ответ 7

Ну, я бы начал с поиска Boost и... hop: Boost.Tokenizer

Хорошая вещь? По умолчанию он разбивается на пробелы и пунктуацию, потому что это означает текст, поэтому вы не забудете символ.

Из введения:

#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

И есть дополнительные возможности:

  • он может скрывать символы
  • он совместим с Iterators, поэтому вы можете использовать его непосредственно с istream... и, таким образом, с помощью ifstream

и несколько параметров (например, сохранение пустых токенов и т.д.)

Проверьте это!