无法用增强精神来解析大文件

时间:2018-11-02 11:11:08

标签: boost locale 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());

但是它的方法不会调用。 因此,我不介意使用非标准代码页读取内存映射文件太难了。我该怎么办?

1 个答案:

答案 0 :(得分:1)

您绝对应该使用¹。

您正在寻找的是Spirit的流迭代器。它有一些预定义(boost::spirit::istream_iterator),但显然由于自定义流,您需要自定义类型。

boost::spirit::istream_iterator的作用是在Multipass Iterator Adapter中包装常规迭代器 wrap 。基本上,它的工作是消除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);

注意:

  1. 我在浏览器中输入了此内容,还没来得及检查
  2. 您可以改用boost::iostreams::stream_buf-也许效率更高(?)
  3. qi::space - qi::eolqi::blank,因此很可能使用boost::spirit::qi::blank_type作为队长效率更高
  4. 注意:根据语法的结构,您可能会遇到糟糕的多遍边缘情况。您可能需要明确何时冲洗(期望点会自动冲洗),例如


¹假设转换完成了您需要他们执行的操作