2010-04-08 25 views
17

Đây phải là một trường hợp lý tưởng để không tái phát minh ra bánh xe, nhưng cho đến nay tìm kiếm của tôi đã vô ích.Tokenizer cho toàn văn

Thay vì viết một bản thân mình, tôi muốn sử dụng trình mã thông báo C++ hiện có. Mã thông báo sẽ được sử dụng trong chỉ mục để tìm kiếm toàn văn bản. Hiệu suất là rất quan trọng, tôi sẽ phân tích nhiều gigabyte văn bản.

Chỉnh sửa: Xin lưu ý rằng mã thông báo sẽ được sử dụng trong chỉ mục tìm kiếm. Tạo các thẻ như vậy không phải là một khoa học chính xác (afaik) và đòi hỏi một số phỏng đoán. Điều này đã được thực hiện một ngàn lần trước đây, và có lẽ trong một ngàn cách khác nhau, nhưng tôi thậm chí không thể tìm thấy một trong số họ :)

Bất kỳ con trỏ tốt?

Cảm ơn!

Trả lời

-1

Tôi đã viết trình mã thông báo của riêng mình như một phần của mã nguồn mở SWISH++ lập chỉ mục và công cụ tìm kiếm.

Ngoài ra còn có ICU tokenizer xử lý Unicode.

1

Nếu hiệu suất là một vấn đề chính có lẽ bạn nên dính vào tốt cũ strtok mà chắc chắn sẽ được nhanh chóng:

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

strtok là ** không ** một tokenizer. Bạn vẫn phải tìm ra sự khác biệt giữa 'class' hoặc' const' hoặc một định danh xảy ra được đặt tên là 'calculate'. –

+3

Trình xác thực * xác định * mã thông báo và mật khẩu * từ khóa * phân loại chúng thành các thẻ (ví dụ: cụm từ "joe eats" -> tokenizer -> {joe, eats} -> lexical analizer -> {(joe, danh từ), (ăn, động từ)}). Tokenization là quá trình * phân định * và ** có thể ** phân loại các phần của một chuỗi các ký tự đầu vào. Trong phân loại sence không phải là tokenizer tăng không phân loại. – clyfe

+0

http://stackoverflow.com/questions/380455/looking-for-a-clear-definition-of-what-a-tokenizer-parser-and-lexers-are-a – clyfe

0

tôi có thể nhìn vào std::stringstream từ <sstream>. C-style strtok có một số vấn đề về khả năng sử dụng và các chuỗi kiểu C chỉ gây rắc rối.

Dưới đây là một ví dụ cực kỳ tầm thường của nó tokenizing một câu diễn tả bằng lời:

#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: 

Lớp std::stringstream là "hai chiều", ở chỗ nó hỗ trợ đầu vào và đầu ra. Bạn có thể muốn làm chỉ một hoặc khác, vì vậy bạn sẽ sử dụng std::istringstream hoặc std::ostringstream.

Vẻ đẹp của họ là họ cũng std::istreamstd::ostream s tương ứng, vì vậy bạn có thể sử dụng chúng như bạn muốn sử dụng std::cin hoặc std::cout, đó là hy vọng quen thuộc với bạn.

Một số có thể cho rằng các lớp này rất tốn kém để sử dụng; std::strstream từ <strstream> chủ yếu là giống nhau, nhưng được xây dựng trên đầu dây C có kiểu 0 giá rẻ hơn. Nó có thể nhanh hơn cho bạn. Nhưng dù sao đi nữa, tôi sẽ không lo lắng về hiệu suất ngay lập tức. Nhận một cái gì đó làm việc, và sau đó điểm chuẩn nó. Rất có thể bạn có thể có đủ tốc độ bằng cách viết đơn giản bằng C++ để giảm thiểu việc tạo và phá hủy đối tượng không cần thiết. Nếu nó vẫn không đủ nhanh, thì bạn có thể tìm ở nơi khác. Tuy nhiên, những lớp này có lẽ đủ nhanh. CPU của bạn có thể lãng phí hàng nghìn chu kỳ trong khoảng thời gian cần để đọc một khối dữ liệu từ một đĩa cứng hoặc mạng.

+1

Đây là một aproach làm một công việc xấu về dấu câu: "Đây là: một câu, với một loạt các từ" -> ("This" "là:" "a" "câu," "với" "một" "bó" "của" "từ"), mặc dù tôi tin rằng nó có thể được overcomed ... cũng tokenizes chỉ trên khoảng trắng: http://codepad.org/m69UhzKN – clyfe

+2

Rõ ràng, do đó bình luận "cực kỳ nhỏ". Tất nhiên có vô số chức năng thành viên của 'std :: istream' sẽ cho phép bạn tùy chỉnh mã thông báo, ví dụ, sử dụng các dấu phân cách khác nhau, v.v. Tôi không gợi ý rằng mã thông báo nên được xây dựng trên đầu toán tử> >, đó là chỉ cho các ví dụ tầm thường. – janks

0

Bạn có thể sử dụng Ragel State Machine Compiler để tạo trình thông báo (hoặc bộ phân tích từ vựng).

Mã được tạo không có phụ thuộc bên ngoài.

Tôi khuyên bạn nên xem mẫu clang.rl để biết ví dụ có liên quan về cú pháp và cách sử dụng.

+0

raegel là trình tạo trình phân tích cú pháp đầy đủ (mặc dù là nhanh), tôi nghĩ nó rất cần thiết cho việc tạo ra chỉ mục (hoặc tạo chỉ mục) (hoặc thậm chí nhiều hơn, hoàn toàn vô dụng) – clyfe

+0

@clyfe: Tôi không nghĩ vậy ... Trình mã hóa riêng của Ragel được viết bằng ragel và mã đầu ra rất nhẹ. – Hasturkun

0

Vâng, tôi sẽ bắt đầu bằng cách tìm kiếm Boost và ... hop: Boost.Tokenizer

Những điều tốt đẹp? Theo mặc định, nó sẽ phá vỡ các khoảng trắng và dấu chấm câu vì nó có nghĩa là cho văn bản, vì vậy bạn sẽ không quên một biểu tượng.

Từ sự ra đời:

#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 

Và có tính năng bổ sung:

  • nó có thể thoát khỏi nhân vật
  • nó tương thích với Iterators để bạn có thể sử dụng nó với một istream trực tiếp .. và do đó có một số ifstream

và một vài tùy chọn (như giữ các thẻ trống ...)

Kiểm tra!

1

Thư viện biểu thức chính quy có thể hoạt động tốt nếu mã thông báo của bạn không quá khó phân tích cú pháp.

15

Các C++ String Toolkit Library (StrTk) có giải pháp sau để vấn đề của bạn:

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

Thêm ví dụ có thể được tìm thấy Here

Các vấn đề liên quan