如何在符号前面的映射值中显示与字符一样多的空格
How to display as many white spaces as characters in a symbol's mapped value in front of it
老实说,我放弃了(像我之前的许多其他人一样)自己寻找这个仍然非常简单的 boost-spirit-karma 库生成器的语法。我想在字符串之前显示与字符串中的字符一样多的白色 spaces:
typedef enum {A, B, C} E;
class EName : public ka::symbols<E, std::string>
{
public:
EName() {add (A,"A") (B,"the B") (C,"a C");}
};
class grm: public ka::grammar<iterator, E()>
{
public:
grm():grm::base_type(start)
{
namespace phx = boost::phoenix;
namespace ka = boost::spirit::karma;
start = ka::duplicate[ka::repeat(phx::bind(&std::string::size,b))[ka::lit(' ')] << b];
}
private:
ka::rule<iterator,E()> start;
EName b;
};
int main(int argc, char * argv[])
{
grm g;
E e = A;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
e = B;
ka::generate(sink,g,e);
std::cout << generated << "\n";
return 0;
}
因此,预期输出是一个白色 space,然后是 "A",在下一行,5 个白色 space,然后是 "the B"(如 "the B" 是一个 5 个字符的字符串)。
我知道在 ka::repeat()[]
生成器的参数上下文中可能无法访问变量 "b"...我尝试 ka::_val
而不是成功。实际上,我在 karma、phoenix 和 fusion 方面都没有足够的经验来构建通往答案的路径,尽管我可能可以访问文档中所有需要的信息。因此,我也很感激一些关于如何仅通过文档(或通过推导)而不是通过经验得出答案的提示。
更新:
我尝试使用属性转换但没有成功:
namespace boost {
namespace spirit {
namespace traits {
template <>
struct transform_attribute<const E, std::string, ka::domain>
{
typedef std::string type;
static type pre(const E & e) {
EName s;
int num = s.find(e)->size();
return std::string(num, ' ');
}
};
} } }
其次是:
start = ka::attr_cast<std::string>(ka::string) << b;
但它也不编译。
我没那么远,所以我 post 这是我的第一次工作尝试。也欢迎其他解决方案。
namespace ka = boost::spirit::karma;
typedef enum {A, B, C} E;
class EName : public ka::symbols<E, std::string>
{
public:
EName() {add (A,"A") (B,"the B") (C,"a C");}
};
namespace boost {
namespace spirit {
namespace traits {
template <>
struct transform_attribute<const E, std::string, ka::domain>
{
typedef std::string type;
static type pre(const E & e) {
EName s;
int num = s.find(e)->size();
return std::string(num, ' ');
}
};
} } }
class grm: public ka::grammar<iterator, E()>
{
public:
grm():grm::base_type(start)
{
start = ka::duplicate[ka::attr_cast<std::string>(ka::string) << b];
}
private:
ka::rule<iterator,E()> start;
EName b;
};
int main(int argc, char * argv[])
{
grm g;
E e = A;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
e = B;
ka::generate(sink,g,e);
std::cout << generated << "\n";
return 0;
}
您的问题可以分为两部分:
- 从枚举值中获取字符串。
- 在该字符串中添加与字符一样多的空格。
问题的第二部分使用 right_align
directive 非常简单。您可以简单地使用:
prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string];
(如果你想使用除了简单的空格之外的其他东西,你可以使用第二个参数到 right_align(例如 ka::right_align(2*phx::size(ka::_val),ka::lit('*'))[ka::string]
))
对于第一部分,您可以用 attr_cast
做一些事情,正如您所展示的那样。在下面的代码中,我使用 phx::bind
来从符号 table.
中获取字符串
#include <iostream>
#include <string>
#include <vector>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace phx = boost::phoenix;
namespace ka = boost::spirit::karma;
typedef enum {A, B, C} E;
class EName : public ka::symbols<E, std::string>
{
public:
EName() {add (A,"A") (B,"the B") (C,"a C");}
};
template <typename Iterator>
class grm: public ka::grammar<Iterator, E()>
{
public:
grm():grm::base_type(start)
{
prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string];
start = prepend_spaces[ka::_1=phx::bind(&EName::at<E>,phx::ref(name),ka::_val)];
}
private:
ka::rule<Iterator,E()> start;
ka::rule<Iterator,std::string()> prepend_spaces;
EName name;
};
int main(int argc, char * argv[])
{
grm<std::back_insert_iterator<std::string> > g;
E e = A;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
e = B;
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
std::vector<E> v {A,B,C};
ka::generate(sink,+g,v);
std::cout << generated << "\n";
return 0;
}
老实说,我放弃了(像我之前的许多其他人一样)自己寻找这个仍然非常简单的 boost-spirit-karma 库生成器的语法。我想在字符串之前显示与字符串中的字符一样多的白色 spaces:
typedef enum {A, B, C} E;
class EName : public ka::symbols<E, std::string>
{
public:
EName() {add (A,"A") (B,"the B") (C,"a C");}
};
class grm: public ka::grammar<iterator, E()>
{
public:
grm():grm::base_type(start)
{
namespace phx = boost::phoenix;
namespace ka = boost::spirit::karma;
start = ka::duplicate[ka::repeat(phx::bind(&std::string::size,b))[ka::lit(' ')] << b];
}
private:
ka::rule<iterator,E()> start;
EName b;
};
int main(int argc, char * argv[])
{
grm g;
E e = A;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
e = B;
ka::generate(sink,g,e);
std::cout << generated << "\n";
return 0;
}
因此,预期输出是一个白色 space,然后是 "A",在下一行,5 个白色 space,然后是 "the B"(如 "the B" 是一个 5 个字符的字符串)。
我知道在 ka::repeat()[]
生成器的参数上下文中可能无法访问变量 "b"...我尝试 ka::_val
而不是成功。实际上,我在 karma、phoenix 和 fusion 方面都没有足够的经验来构建通往答案的路径,尽管我可能可以访问文档中所有需要的信息。因此,我也很感激一些关于如何仅通过文档(或通过推导)而不是通过经验得出答案的提示。
更新:
我尝试使用属性转换但没有成功:
namespace boost {
namespace spirit {
namespace traits {
template <>
struct transform_attribute<const E, std::string, ka::domain>
{
typedef std::string type;
static type pre(const E & e) {
EName s;
int num = s.find(e)->size();
return std::string(num, ' ');
}
};
} } }
其次是:
start = ka::attr_cast<std::string>(ka::string) << b;
但它也不编译。
我没那么远,所以我 post 这是我的第一次工作尝试。也欢迎其他解决方案。
namespace ka = boost::spirit::karma;
typedef enum {A, B, C} E;
class EName : public ka::symbols<E, std::string>
{
public:
EName() {add (A,"A") (B,"the B") (C,"a C");}
};
namespace boost {
namespace spirit {
namespace traits {
template <>
struct transform_attribute<const E, std::string, ka::domain>
{
typedef std::string type;
static type pre(const E & e) {
EName s;
int num = s.find(e)->size();
return std::string(num, ' ');
}
};
} } }
class grm: public ka::grammar<iterator, E()>
{
public:
grm():grm::base_type(start)
{
start = ka::duplicate[ka::attr_cast<std::string>(ka::string) << b];
}
private:
ka::rule<iterator,E()> start;
EName b;
};
int main(int argc, char * argv[])
{
grm g;
E e = A;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
e = B;
ka::generate(sink,g,e);
std::cout << generated << "\n";
return 0;
}
您的问题可以分为两部分:
- 从枚举值中获取字符串。
- 在该字符串中添加与字符一样多的空格。
问题的第二部分使用 right_align
directive 非常简单。您可以简单地使用:
prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string];
(如果你想使用除了简单的空格之外的其他东西,你可以使用第二个参数到 right_align(例如 ka::right_align(2*phx::size(ka::_val),ka::lit('*'))[ka::string]
))
对于第一部分,您可以用 attr_cast
做一些事情,正如您所展示的那样。在下面的代码中,我使用 phx::bind
来从符号 table.
#include <iostream>
#include <string>
#include <vector>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace phx = boost::phoenix;
namespace ka = boost::spirit::karma;
typedef enum {A, B, C} E;
class EName : public ka::symbols<E, std::string>
{
public:
EName() {add (A,"A") (B,"the B") (C,"a C");}
};
template <typename Iterator>
class grm: public ka::grammar<Iterator, E()>
{
public:
grm():grm::base_type(start)
{
prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string];
start = prepend_spaces[ka::_1=phx::bind(&EName::at<E>,phx::ref(name),ka::_val)];
}
private:
ka::rule<Iterator,E()> start;
ka::rule<Iterator,std::string()> prepend_spaces;
EName name;
};
int main(int argc, char * argv[])
{
grm<std::back_insert_iterator<std::string> > g;
E e = A;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
e = B;
ka::generate(sink,g,e);
std::cout << generated << "\n";
generated.clear();
std::vector<E> v {A,B,C};
ka::generate(sink,+g,v);
std::cout << generated << "\n";
return 0;
}