如何将 boost::spirit X3 与 QString 结合使用?
How can I use boost::spirit X3 in conjunction with QString?
Boost 有一个名为 Spirit 的库,它大量使用 TMP 以便于在类似 BNF 的语法中轻松创建解析器。默认情况下,它旨在与标准库字符串一起使用。我在基于 Qt 的项目中使用它,其中 QString
是主要字符串类型。如何将 boost::spirit
与 QString
一起使用?
让boost::spirit
和QString
合作有两个部分;获取数据和获取数据。我们将从后者开始。就boost::spirit
而言,QString
是未知类型。我们必须给它一些容器特征,以便它知道如何交互:
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <QString>
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<>
struct push_back_container<QString>
{
template<typename T>
static bool call(QString& c, T&& val)
{
c.push_back(std::move(val));
return true;
}
};
template<>
struct append_container<QString>
{
template<typename Iterator>
static bool call(QString& c, Iterator first, Iterator last)
{
c.append(first, std::distance(first, last));
return true;
}
};
template<>
struct is_empty_container<QString>
{
static bool call(QString const& c)
{
return c.isEmpty();
}
};
}}}}
根据您的特定用例,您可能还想从 QString
解析 。可能有一种方法可以教 boost::spirit
关于 QChar
(QString
的可迭代类型),但我没有耐心。另一种方法是创建一个 iterator_adaptor
,其值类型为 char16_t
。尽管 uint32_t
是 boost::spirit
用来表示 unicode 值的类型,它不能明确地转换为 QChar
而 char16_t
可以。 QString
是在UTF16基础上运行的,所以这个类型足够宽了。请注意,您需要打开 unicode 支持 (#define BOOST_SPIRIT_X3_UNICODE
)。
#include <boost/iterator/iterator_adaptor.hpp>
#include <QString>
template<typename QStringIterator>
class QStringSpiritUnicodeIteratorAdaptor : public boost::iterator_adaptor<
QStringSpiritUnicodeIteratorAdaptor<QStringIterator>,
QStringIterator, char16_t, boost::forward_traversal_tag, char16_t>
{
public:
using boost::iterator_adaptor<
QStringSpiritUnicodeIteratorAdaptor<QStringIterator>,
QStringIterator, char16_t, boost::forward_traversal_tag,
char16_t>::iterator_adaptor;
private:
friend class boost::iterator_core_access;
char16_t dereference() const
{
return static_cast<char16_t>(this->base_reference()->unicode());
}
};
using QStringSpiritUnicodeIterator =
QStringSpiritUnicodeIteratorAdaptor<QString::iterator>;
using QStringSpiritUnicodeConstIterator =
QStringSpiritUnicodeIteratorAdaptor<QString::const_iterator>;
这个用法如下:
QString text = "blah blah blah";
QStringSpiritUnicodeIterator begin(text.begin());
QStringSpiritUnicodeIterator end(text.end());
...::x3::phrase_parse(begin, end, ...);
Boost 有一个名为 Spirit 的库,它大量使用 TMP 以便于在类似 BNF 的语法中轻松创建解析器。默认情况下,它旨在与标准库字符串一起使用。我在基于 Qt 的项目中使用它,其中 QString
是主要字符串类型。如何将 boost::spirit
与 QString
一起使用?
让boost::spirit
和QString
合作有两个部分;获取数据和获取数据。我们将从后者开始。就boost::spirit
而言,QString
是未知类型。我们必须给它一些容器特征,以便它知道如何交互:
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <QString>
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<>
struct push_back_container<QString>
{
template<typename T>
static bool call(QString& c, T&& val)
{
c.push_back(std::move(val));
return true;
}
};
template<>
struct append_container<QString>
{
template<typename Iterator>
static bool call(QString& c, Iterator first, Iterator last)
{
c.append(first, std::distance(first, last));
return true;
}
};
template<>
struct is_empty_container<QString>
{
static bool call(QString const& c)
{
return c.isEmpty();
}
};
}}}}
根据您的特定用例,您可能还想从 QString
解析 。可能有一种方法可以教 boost::spirit
关于 QChar
(QString
的可迭代类型),但我没有耐心。另一种方法是创建一个 iterator_adaptor
,其值类型为 char16_t
。尽管 uint32_t
是 boost::spirit
用来表示 unicode 值的类型,它不能明确地转换为 QChar
而 char16_t
可以。 QString
是在UTF16基础上运行的,所以这个类型足够宽了。请注意,您需要打开 unicode 支持 (#define BOOST_SPIRIT_X3_UNICODE
)。
#include <boost/iterator/iterator_adaptor.hpp>
#include <QString>
template<typename QStringIterator>
class QStringSpiritUnicodeIteratorAdaptor : public boost::iterator_adaptor<
QStringSpiritUnicodeIteratorAdaptor<QStringIterator>,
QStringIterator, char16_t, boost::forward_traversal_tag, char16_t>
{
public:
using boost::iterator_adaptor<
QStringSpiritUnicodeIteratorAdaptor<QStringIterator>,
QStringIterator, char16_t, boost::forward_traversal_tag,
char16_t>::iterator_adaptor;
private:
friend class boost::iterator_core_access;
char16_t dereference() const
{
return static_cast<char16_t>(this->base_reference()->unicode());
}
};
using QStringSpiritUnicodeIterator =
QStringSpiritUnicodeIteratorAdaptor<QString::iterator>;
using QStringSpiritUnicodeConstIterator =
QStringSpiritUnicodeIteratorAdaptor<QString::const_iterator>;
这个用法如下:
QString text = "blah blah blah";
QStringSpiritUnicodeIterator begin(text.begin());
QStringSpiritUnicodeIterator end(text.end());
...::x3::phrase_parse(begin, end, ...);