用于全文的Tokenizer

时间:2010-04-08 14:24:51

标签: c++ full-text-search tokenize

这应该是不重新发明轮子的理想情况,但到目前为止,我的搜索一直是徒劳。

我不想自己写一个,而是想使用现有的C ++标记器。令牌将用于全文搜索的索引中。性能非常重要,我将解析许多千兆字节的文本。

编辑:请注意,令牌将用于搜索索引。创建这样的令牌并不是一门精确的科学(afaik),需要一些启发式方法。这已经做了一千次,可能有千种不同的方式,但我甚至找不到其中一种:)

有什么好的指示?

谢谢!

7 个答案:

答案 0 :(得分:16)

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

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

   return 0;
}

可以找到更多示例Here

答案 1 :(得分:1)

如果表现是一个主要问题,你应该坚持使用肯定会很快的好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;
}

答案 2 :(得分:1)

如果您的令牌不太难解析,正则表达式库可能会运行良好。

答案 3 :(得分:0)

我可以从std::stringstream查看<sstream>。 C风格的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;
   }
}

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:

std::stringstream类是“双向的”,因为它支持输入和输出。您可能只想做其中一个,因此您可以使用std::istringstreamstd::ostringstream

他们的魅力在于它们也分别是std::istreamstd::ostream,因此您可以在使用std::cinstd::cout时使用它们希望你熟悉。

有些人可能认为这些课程使用起来很昂贵;来自std::strstream的{​​{1}}大致相同,但建立在更便宜的C风格0终止字符串之上。它可能会更快。但无论如何,我不会马上担心表现。获取一些有效的东西,然后对其进您可以通过编写编写良好的C ++来最大限度地减少不必要的对象创建和破坏,从而获得足够的速度。如果它仍然不够快,那么你可以看看其他地方。但是,这些类可能足够快。在从硬盘或网络读取数据块所需的时间内,您的CPU可能会浪费数千个周期。

答案 4 :(得分:0)

您可以使用Ragel State Machine Compiler创建一个标记器(或词法分析器)。

生成的代码没有外部依赖关系。

我建议您查看clang.rl示例以获取语法和用法的相关示例。

答案 5 :(得分:0)

好吧,我会先搜索Boost然后......跳: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

和一些选项(比如保留空标记等......)

看看吧!

答案 6 :(得分:0)

我将自己的tokenizer编写为开源的一部分 SWISH++索引和搜索引擎。

还有ICU tokenizer 处理Unicode。