Ответ 1
Я написал свой собственный токенизатор как часть открытого исходного кода SWISH ++ индексирование и поисковая система.
Также существует токен-генератор ICU который обрабатывает Unicode.
Это должен быть идеальный случай не изобретать колесо, но до сих пор мой поиск был тщетным.
Вместо того, чтобы писать сам, я хотел бы использовать существующий токенизатор С++. Токены должны использоваться в индексе полнотекстового поиска. Производительность очень важна, я буду разбирать много гигабайт текста.
Изменить: обратите внимание, что маркеры должны использоваться в индексе поиска. Создание таких токенов не является точной наукой (afaik) и требует некоторой эвристики. Это было сделано тысячу раз раньше и, вероятно, тысячами разных способов, но я даже не могу найти их:)
Любые хорошие указатели?
Спасибо!
Я написал свой собственный токенизатор как часть открытого исходного кода SWISH ++ индексирование и поисковая система.
Также существует токен-генератор ICU который обрабатывает Unicode.
С++ 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;
}
Дополнительные примеры можно найти здесь
Если производительность является основной проблемой, вы должны, вероятно, придерживаться старой доброй 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;
}
Библиотека регулярных выражений может работать хорошо, если ваши токены не слишком сложны для анализа.
Я мог бы заглянуть в 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-стиля. Это может быть быстрее для вас. Но в любом случае, я бы не стал беспокоиться о производительности сразу. Получите что-то работающее, а затем сравните его. Скорее всего, вы можете получить достаточную скорость, просто написав хорошо написанный С++, который минимизирует ненужное создание и уничтожение объектов. Если это еще не достаточно быстро, вы можете посмотреть в другом месте. Тем не менее, эти классы, вероятно, достаточно быстры. Ваш процессор может тратить тысячи циклов на время, затрачиваемое на чтение блока данных с жесткого диска или сети.
Вы можете использовать Ragel State Machine Compiler для создания токенизатора (или лексического анализатора).
Сгенерированный код не имеет внешних зависимостей.
Я предлагаю вам посмотреть пример clang.rl для соответствующего примера синтаксиса и использования.
Ну, я бы начал с поиска 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
и несколько параметров (например, сохранение пустых токенов и т.д.)
Проверьте это!