- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
考虑从更复杂的代码中提取的以下示例:
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <map>
#include <string>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
// The class implements a XML tag storing the name and a variable number of attributes:
struct Tag
{
// The typedef defines the type used for a XML name:
typedef std::string name_type;
// The typedef defines the type used for a XML value:
typedef std::string value_type;
// The typedef defines the type of a XML attribute:
typedef std::pair<
name_type,
value_type
> attribute_type;
// The type defines a list of attributes.
// Note: We use a std::map to simplify the attribute search.
typedef std::map<
name_type,
value_type
> list_type;
// Clear all information stored within the instance:
void clear( )
{
m_name.clear( ); m_attribute.clear( );
}
std::size_t m_indent; // The tag shall be / is indented by m_indent number of tabs.
name_type m_name; // Name of the tag.
list_type m_attribute; // List of tag attributes.
};
// Define the mapping between Tools::Serialization::Archive::Type::Xml::Format::Tag and boost::fusion:
BOOST_FUSION_ADAPT_STRUCT( Tag,
( std::size_t , m_indent )
( Tag::name_type, m_name )
( Tag::list_type, m_attribute ) )
// This class implements the decoder skipper grammar:
template < typename _Iterator >
struct skipper
: qi::grammar< _Iterator >
{
skipper( ) : skipper::base_type( m_skipper )
{
// The rule defines the default skipper grammar:
m_skipper = ( qi::space ) // Skip all "spaces".
|
( qi::cntrl ); // Skip all "cntrl".
}
// The following variables define the rules used within this grammar:
qi::rule< _Iterator > m_skipper;
};
// This class implements the grammar used to parse a XML "begin tag".
// The expected format is as follows: <name a="xyz" b="xyz" ... N="xyz">
template < typename _Iterator, typename _Skipper >
struct tag_begin : qi::grammar< _Iterator, Tag( ), _Skipper >
{
tag_begin( ) : tag_begin::base_type( m_tag )
{
// The rule for a XML name shall stop when a ' ' or '>' is detected:
m_string = qi::lexeme[ *( qi::char_( "a-zA-Z0-9_.:" ) ) ];
// The rule for a XML attribute shall parse the following format: 'name="value"':
m_attribute = m_string
>> "=\""
>> m_string
>> '"';
// The rule for an XML attribute list is a sequence of attributes separated by ' ':
m_list = *( m_attribute - '>' );
// Finally the resulting XML tag has the following format: <name a="xyz" b="xyz" ... N="xyz">
m_tag = '<'
>> -qi::int_
>> m_string
>> m_list
>> '>';
// Enable debug support for the used rules. To activate the debug output define macro BOOST_SPIRIT_DEBUG:
BOOST_SPIRIT_DEBUG_NODES( ( m_string )( m_attribute )( m_list ) )
}
// The following variables define the rules used within this grammar:
qi::rule< _Iterator, Tag::name_type( ) , _Skipper > m_string;
qi::rule< _Iterator, Tag::attribute_type( ), _Skipper > m_attribute;
qi::rule< _Iterator, Tag::list_type( ) , _Skipper > m_list;
qi::rule< _Iterator, Tag( ) , _Skipper > m_tag;
};
bool beginTag( std::istream& stream, Tag& tag )
{
// Ensure that no whitespace characters are skipped:
stream.unsetf( std::ios::skipws );
// Create begin and end iterator for given stream:
boost::spirit::istream_iterator begin( stream );
boost::spirit::istream_iterator end;
// Define the grammar skipper type:
typedef skipper<
boost::spirit::istream_iterator
> skipper_type;
// Create an instance of the used skipper:
skipper_type sk;
// Create an instance of the used grammar:
tag_begin<
boost::spirit::istream_iterator,
skipper_type
> gr;
// Try to parse the data stored within the stream according the grammar and store the result in the tag variable:
bool r = boost::spirit::qi::phrase_parse( begin,
end,
gr,
sk,
tag );
char nextSym = 0;
stream >> nextSym;
for( auto i = tag.m_attribute.begin( ); i != tag.m_attribute.end( ); ++i )
{
std::cout << i->first << " : " << i->second << std::endl;
}
std::cout << "Next symbol: " << nextSym << std::endl;
return r;
}
int main( )
{
std::stringstream s;
s << "<object cName=\"bool\" cVersion=\"1\" vName=\"bool\"> <value>0</value></object>";
Tag t;
beginTag( s, t );
return 0;
}
我使用语法提取xml标签内容。原则上这按预期工作,结果如下:
cName : bool
cVersion : 1
vName : bool
Next symbol: v
问题是解析器消耗了太多数据。我的期望是解析器在第一个标记关闭“>”时停止。但似乎解析器还使用了以下空格和“<”符号。所以从流中读取的下一个符号等于'v'。我想避免这种情况,因为以下解析器调用需要“<”符号。有什么想法吗?
最佳答案
没有可靠的方法来实现这一点。
问题是您没有在解析调用中重复使用 istream_iterator
。 boost::spirit::istream_iterator
的全部目的是在 InputIterator¹ 之上提供一个具有 multi_pass
功能的迭代器。
因为 Spirit 允许具有任意回溯的任意语法,所以您无法避免消耗比实际成功解析的输入更多的输入。
这里显而易见的解决方案是将所有后续步骤集成到相同的语法和/或重用迭代器(因此迭代器存储的回溯缓冲区仍然包含您需要的字符)。
这是一个循环解析打开标签的版本
while (boost::spirit::qi::phrase_parse(begin, end, gr, sk, tag)) {
std::cout << "============\nParsed open tag '" << tag.m_name << "'\n";
for (auto const& p: tag.m_attribute)
std::cout << p.first << ": " << p.second << "\n";
count += 1;
tag.clear();
};
std::cout << "Next symbol: ";
std::copy(begin, end, std::ostream_iterator<char>(std::cout));
它打印:
============
Parsed open tag 'object'
cName: bool
cVersion: 1
vName: bool
============
Parsed open tag 'value'
Next symbol: 0</value>
</object>
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
namespace qi = boost::spirit::qi;
// The class implements a XML tag storing the name and a variable number of
// attributes:
struct Tag {
typedef std::string name_type;
typedef std::string value_type;
typedef std::pair<name_type, value_type> attribute_type;
typedef std::map<name_type, value_type> list_type;
// Clear all information stored within the instance:
void clear() {
m_name.clear();
m_attribute.clear();
}
std::size_t m_indent; // The tag shall be / is indented by m_indent number of tabs.
name_type m_name; // Name of the tag.
list_type m_attribute; // List of tag attributes.
};
BOOST_FUSION_ADAPT_STRUCT(Tag, m_indent, m_name, m_attribute)
// This class implements the grammar used to parse a "XML" begin tag.
// The expected format is as follows: <name a="xyz" b="xyz" ... N="xyz">
template <typename Iterator, typename Skipper> struct tag_begin : qi::grammar<Iterator, Tag(), Skipper> {
tag_begin() : tag_begin::base_type(m_tag) {
m_string = *qi::char_("a-zA-Z0-9_.:");
m_attribute = m_string >> '=' >> qi::lexeme['"' >> m_string >> '"'];
m_attributes = *m_attribute;
m_tag = '<' >> -qi::int_ >> m_string >> m_attributes >> '>';
BOOST_SPIRIT_DEBUG_NODES((m_string)(m_attribute)(m_attributes))
}
private:
// The following variables define the rules used within this grammar:
qi::rule<Iterator, Tag::attribute_type(), Skipper> m_attribute;
qi::rule<Iterator, Tag::list_type(), Skipper> m_attributes;
qi::rule<Iterator, Tag(), Skipper> m_tag;
// lexemes
qi::rule<Iterator, Tag::name_type()> m_string;
};
bool beginTag(std::istream &stream, Tag &tag) {
// Ensure that no whitespace characters are skipped:
stream.unsetf(std::ios::skipws);
typedef boost::spirit::istream_iterator It;
typedef qi::rule<It> skipper_type;
skipper_type sk = qi::space | qi::cntrl;
tag_begin<boost::spirit::istream_iterator, skipper_type> gr;
It begin(stream), end;
int count = 0;
while (boost::spirit::qi::phrase_parse(begin, end, gr, sk, tag)) {
std::cout << "============\nParsed open tag '" << tag.m_name << "'\n";
for (auto const& p: tag.m_attribute)
std::cout << p.first << ": " << p.second << "\n";
count += 1;
tag.clear();
};
std::cout << "Next symbol: ";
std::copy(begin, end, std::ostream_iterator<char>(std::cout));
return count > 0;
}
int main() {
std::stringstream s;
s << R"(
<object cName="bool" cVersion="1" vName="bool">
<value>0</value>
</object>
)";
Tag t;
beginTag(s, t);
}
¹(严格向前,不能重复取消引用)
关于c++ - boost spirit istream_iterator 从流中消耗太多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35256521/
#include #include #include #include using namespace std; int main() { vector v(istream_itera
嗨,我希望有人能帮助理解下面代码的这种行为。 #include #include #include #include #include #include #include struct
我尝试实现“C++ 标准库”第 107 页中的流迭代器示例。我被困在这条线上: copy (istream_iterator(cin), istream_iterator(), back_insert
我在将 istream_iterator 用于我需要的目的时遇到困难。我有一个文件,我想将其逐行读取到一个集合中。我必须使用迭代器,我想知道我的代码或我的方法是否有问题。 非常感谢您的帮助。这是我正在
好吧,你们对我的最后一个问题很有帮助,所以我会尝试另一个问题。这也是作业,虽然上一个很旧,但已提交并等待标记。所以如果有什么东西会咬我,那可能就是这个问题。我混淆了类(class)名称等,因为仍然可以
我有两段代码。它们在 main() 中单独使用时可以正常工作。 vector v; cout start_cin(cin); istream_iterator end_of_cin; copy(st
我不明白为什么第二个参数 for_each 是一个空迭代器。有人可以向我解释一下吗? fstream("datfile.txt"); for_each(istream_iterator(datfile
给定一个包含以下十六进制代码的文件:0B 00 00 00 00 00 20 41 我正在尝试填充一个 std::vector ,然后手动检查每个字节。 这是我使用迭代器构造函数从两个 std::is
我尝试实现“C++ 标准库”第 107 页中的流迭代器示例。我被困在这条线上: copy (istream_iterator(cin), istream_iterator(), back_insert
给定一个包含以下十六进制代码的文件:0B 00 00 00 00 00 20 41 我正在尝试填充一个 std::vector ,然后手动检查每个字节。 这是我使用迭代器构造函数从两个 std::is
这是一个 Minimal, Complete, Verifiable Example我知道这不是copacetic。无论如何,给定结构: struct Foo { int even;
如果您将输入编码为 std::istream_iterator ii(std::cin); std::istream_iterator eos; std::for_each(ii,eos,record
我从标准输入得到以下输入: 2 5 2 1 5 3 4 5 2 5 1 3 4 第一行代表队列数(我们称这个值为n)。然后,对于每个队列,在第一行有一个值 l 表示队列的长度,后面是实际队列。 我正在
我正在尝试通过使用 std::distance 作为 vector 的构造函数参数来计算 std::cin 读取的元素数量,就像这样: // Gives correct amount, but now
我编写了以下程序,从 std::cin 读取 3 个数字,并将它们输出到 std::cout , 并执行两次: #include #include #include int main() {
在这种情况下,当从控制台获取字符串输入时,源代码结尾是什么? int main() { std::vector str; copy (istream_iterator(std::cin),
我在 istream_iterator 读取文件时遇到问题,因为它会忽略空行,但我需要将这些空行包含为“”。 我应该如何修改下面的程序以获得 vector 中的 5 条线? #include #in
我想读取以下输入: Foo 1 2 4 Bar 3 4 5 作为两个独立的“字符串”对象。 是否可以使用 istream_iterator 来完成此操作? 我在哪里可以找到所有这些迭代器的好文档? 最
我可以在两个 istream_iterators 之间进行赋值操作吗?如果是这样,那么行为会是什么,即两个迭代器是否会指向文件中的同一位置,即我们会得到两个指向文件中同一行的指针吗? 如果是这样,我可
我正在尝试从 ifstream fin 中读取并使用 istream_iterators 将其放入 vector vec1 中。我到处都看到了这些东西: vector vec1((istream_it
我是一名优秀的程序员,十分优秀!