这应该是不重新发明轮子的理想情况,但到目前为止,我的搜索一直是徒劳。
我不想自己写一个,而是想使用现有的C ++标记器。令牌将用于全文搜索的索引中。性能非常重要,我将解析许多千兆字节的文本。
编辑:请注意,令牌将用于搜索索引。创建这样的令牌并不是一门精确的科学(afaik),需要一些启发式方法。这已经做了一千次,可能有千种不同的方式,但我甚至找不到其中一种:)
有什么好的指示?
谢谢!
答案 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::istringstream
或std::ostringstream
。
他们的魅力在于它们也分别是std::istream
和std::ostream
,因此您可以在使用std::cin
或std::cout
时使用它们希望你熟悉。
有些人可能认为这些课程使用起来很昂贵;来自std::strstream
的{{1}}大致相同,但建立在更便宜的C风格0终止字符串之上。它可能会更快。但无论如何,我不会马上担心表现。获取一些有效的东西,然后对其进您可以通过编写编写良好的C ++来最大限度地减少不必要的对象创建和破坏,从而获得足够的速度。如果它仍然不够快,那么你可以看看其他地方。但是,这些类可能足够快。在从硬盘或网络读取数据块所需的时间内,您的CPU可能会浪费数千个周期。
答案 4 :(得分:0)
答案 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。