Spirit X3:解析单个字符并生成字符串的规则
Spirit X3: Rule that parses a single character and generates a string
是否可以在 Spirit X3 中创建一个解析单个字符并生成字符串的规则?
我想在版本号解析器的上下文中使用它,其中每个数字标识符可以是单个数字,也可以是非零数字后跟一个或多个数字:
auto const positive_digit = char_(L"123456789");
auto const digit = char_(L"0123456789");
auto const digits = x3::rule<class digits, std::wstring>{"digits"} = +digit;
auto const numeric_identifier = (positive_digit >> digits) | digit;
我看到的问题是 numeric_identifier
合成的类型与字符串不兼容(参见完整示例 here)。
为了解决这个问题,我需要创建一个匹配数字并合成字符串的规则。我能想到的唯一解决方案是使用语义操作,但是当在需要回溯的情况下使用规则时,这会导致错误(参见完整示例 here)。
这很棘手。我不知道是否有更好的方法来匹配字符并获取字符串作为解析输出,但一种方法是利用序列运算符 >>
将字符序列传播为字符串这一事实.
在您的规则中,由于 numeric_identifier
是一串数字或单个数字,您可以使用一个事实,即单个数字后跟输入结束符来制作一个序列,将其转换成一个字符串:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
namespace x3 = boost::spirit::x3;
auto const positive_digit = x3::char_("123456789");
auto const digit = x3::char_("0123456789");
auto const numeric_identifier = (digit >> x3::eoi) | (positive_digit >> (+digit)) ;
int main() {
std::string test = "1";
std::string numeric_identifier_str;
bool success = x3::parse(test.begin(), test.end(), numeric_identifier, numeric_identifier_str);
std::cout << (success ? "success" : "failure") << " " << numeric_identifier_str << "\n";
test = "4545631";
numeric_identifier_str = "";
success = x3::parse(test.begin(), test.end(), numeric_identifier, numeric_identifier_str);
std::cout << (success ? "success" : "failure") << " " << numeric_identifier_str;
}
产量
success 1
success 44545631
我不太清楚你要做什么。如果目标是验证字符串的格式但解析完全匹配输入字符串,为什么不使用 x3::raw
?
例如
auto num_id = x3::uint_;
auto version = x3::raw[num_id % '.'];
现在可以直接将典型的版本字符串解析成字符串:
int main() {
for (sv input : {"0", "1", "1.4", "1.6.77.0.1234",}) {
std::string parsed;
std::cout << "Parsing " << std::quoted(input);
auto f = begin(input), l = end(input);
if (parse(f, l, version, parsed)) {
std::cout << " -> " << std::quoted(parsed) << "\n";
} else {
std::cout << " -- FAILED\n";
}
if (f != l) {
std::cout << "Remaining unparsed: " << std::quoted(sv{f, l}) << "\n";
}
}
}
版画
Parsing "0" -> "0"
Parsing "1" -> "1"
Parsing "1.4" -> "1.4"
Parsing "1.6.77.0.1234" -> "1.6.77.0.1234"
添加 ID 号码不以 0
开头的限制,除非它们是字面上的 zero
:
auto num_id = x3::char_('0') | x3::uint_;
当然你可以不那么聪明,也可以更直率:
auto num_id
= !x3::lit('0') >> x3::uint_
| x3::uint_parser<unsigned, 10, 1, 1>{};
效果是一样的。我比较喜欢第一个。
是否可以在 Spirit X3 中创建一个解析单个字符并生成字符串的规则?
我想在版本号解析器的上下文中使用它,其中每个数字标识符可以是单个数字,也可以是非零数字后跟一个或多个数字:
auto const positive_digit = char_(L"123456789");
auto const digit = char_(L"0123456789");
auto const digits = x3::rule<class digits, std::wstring>{"digits"} = +digit;
auto const numeric_identifier = (positive_digit >> digits) | digit;
我看到的问题是 numeric_identifier
合成的类型与字符串不兼容(参见完整示例 here)。
为了解决这个问题,我需要创建一个匹配数字并合成字符串的规则。我能想到的唯一解决方案是使用语义操作,但是当在需要回溯的情况下使用规则时,这会导致错误(参见完整示例 here)。
这很棘手。我不知道是否有更好的方法来匹配字符并获取字符串作为解析输出,但一种方法是利用序列运算符 >>
将字符序列传播为字符串这一事实.
在您的规则中,由于 numeric_identifier
是一串数字或单个数字,您可以使用一个事实,即单个数字后跟输入结束符来制作一个序列,将其转换成一个字符串:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
namespace x3 = boost::spirit::x3;
auto const positive_digit = x3::char_("123456789");
auto const digit = x3::char_("0123456789");
auto const numeric_identifier = (digit >> x3::eoi) | (positive_digit >> (+digit)) ;
int main() {
std::string test = "1";
std::string numeric_identifier_str;
bool success = x3::parse(test.begin(), test.end(), numeric_identifier, numeric_identifier_str);
std::cout << (success ? "success" : "failure") << " " << numeric_identifier_str << "\n";
test = "4545631";
numeric_identifier_str = "";
success = x3::parse(test.begin(), test.end(), numeric_identifier, numeric_identifier_str);
std::cout << (success ? "success" : "failure") << " " << numeric_identifier_str;
}
产量
success 1
success 44545631
我不太清楚你要做什么。如果目标是验证字符串的格式但解析完全匹配输入字符串,为什么不使用 x3::raw
?
例如
auto num_id = x3::uint_;
auto version = x3::raw[num_id % '.'];
现在可以直接将典型的版本字符串解析成字符串:
int main() {
for (sv input : {"0", "1", "1.4", "1.6.77.0.1234",}) {
std::string parsed;
std::cout << "Parsing " << std::quoted(input);
auto f = begin(input), l = end(input);
if (parse(f, l, version, parsed)) {
std::cout << " -> " << std::quoted(parsed) << "\n";
} else {
std::cout << " -- FAILED\n";
}
if (f != l) {
std::cout << "Remaining unparsed: " << std::quoted(sv{f, l}) << "\n";
}
}
}
版画
Parsing "0" -> "0"
Parsing "1" -> "1"
Parsing "1.4" -> "1.4"
Parsing "1.6.77.0.1234" -> "1.6.77.0.1234"
添加 ID 号码不以 0
开头的限制,除非它们是字面上的 zero
:
auto num_id = x3::char_('0') | x3::uint_;
当然你可以不那么聪明,也可以更直率:
auto num_id
= !x3::lit('0') >> x3::uint_
| x3::uint_parser<unsigned, 10, 1, 1>{};
效果是一样的。我比较喜欢第一个。