[英]How to incrementally parse (and act on) a large file with Boost.Spirit.Qi?
[英]Can not parse large file with boost spirit
我有一個大文件。 它的代碼頁是 CP1251。 我想用提升精神來解析它。 當解析器遇到非標准字符時,我成功解析了它。 提升文檔說:
內存映射文件設備的寬字符版本可以使用模板 code_converter 定義如下:
#include <boost/iostreams/code_converter.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
typedef code_converter<mapped_file_source> wmapped_file_source;
typedef code_converter<mapped_file_sink> wmapped_file_sink;
但我應該使用它嗎? 我的代碼我不應該有水槽。 我想:我的解析器使用源代碼中的迭代器,code_converter 使用我給他的代碼頁轉換它們,並將翻譯后的字符發送到解析器並解析文件。
所以,這是我的代碼的一部分,它不起作用:
typedef boost::iostreams::code_converter<boost::iostreams::mapped_file> wmapped_file_source;
boost::locale::generator gen;
std::locale lru = gen("ru_RU.CP1251");
wmapped_file_source mmap;
mmap.imbue(lru);
mmap.open(current_task.filename);
RhAst::RhFile rh_file(this);
bool res = phrase_parse(mmap->begin(), mmap->end(), parser, space - eol, rh_file);
我嘗試創建自己的語言環境對象:
class LocaleRus : public std::codecvt<wchar_t, char, std::mbstate_t>
{
public:
explicit LocaleRus(size_t r = 0) : std::codecvt <wchar_t, char, std::mbstate_t> ( r )
{
}
protected:
result do_in ( state_type&, const char* from, const char* from_end, const char*& from_next, char* to, char*, char*& to_next ) const
{
const int size = from_end - from;
//::OemToCharBuff ( from, to, size );
from_next = from + size;
to_next = to + size ;
return ok;
}
result do_out ( state_type&, const char* from, const char* from_end, const char*& from_next, char* to, char*, char*& to_next ) const
{
const int size = from_end - from;
//::CharToOemBuff ( from, to, size );
from_next = from + size;
to_next = to + size ;
return ok;
}
result do_unshift ( state_type&, char*, char*, char*& ) const { return ok; }
int do_encoding () const throw () { return 1; }
bool do_always_noconv () const throw () { return false; }
int do_length ( state_type& state, const char* from, const char* from_end, size_t max ) const
{
return std::codecvt <wchar_t, char, std::mbstate_t>::do_length ( state, from, from_end, max );
}
int do_max_length () const throw ()
{
return std::codecvt <wchar_t, char, std::mbstate_t>::do_max_length ();
}
};
並在代碼中使用它:
std::locale lru(std::locale(), new LocaleRus());
但它的方法不會調用。 所以,我不介意用非標准代碼頁讀取內存映射文件太難了。 我做錯了什么?
你應該使用它¹,絕對。
您正在尋找的是 Spirit 的流迭代器。 它有一些預定義的( boost::spirit::istream_iterator
),但顯然你需要自定義類型,因為自定義流。
boost::spirit::istream_iterator
所做的是在Multipass Iterator Adapter 中包裝一個常規迭代器。 基本上它的作用是消除InputIterator的只進和一次性使用限制。
它通過保留用於回溯的緩沖區來實現。
我認為你應該能夠使用類似的東西:
boost::locale::generator gen;
std::locale lru = gen("ru_RU.CP1251");
typedef boost::iostreams::code_converter<boost::iostreams::mapped_file> wmapped_file_source;
wmapped_file_source mmap;
mmap.imbue(lru);
mmap.open(current_task.filename);
RhAst::RhFile rh_file(this);
boost::iostreams::stream<wmapped_file_source> map_source(mmap);
typedef std::istreambuf_iterator<char> base_iterator_type;
spirit::multi_pass<base_iterator_type>
first = spirit::make_default_multi_pass(base_iterator_type(map_source)),
last = spirit::make_default_multi_pass(base_iterator_type());
bool res = qi::phrase_parse(first, last, parser, qi::blank, rh_file);
筆記:
boost::iostreams::stream_buf
- 也許效率更高(?)qi::space - qi::eol
是qi::blank
,因此可能使用boost::spirit::qi::blank_type
作為船長效率更高當心:根據您的語法結構,您可能會遇到糟糕的多遍邊緣情況。 您可能希望明確何時刷新(期望點會自動執行此操作),請參見例如
¹假設轉換做你需要他們做的事情
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.