I'd personally write it "positively":
auto const rule = raw [ lexeme [
alnum >> *('-' >> alnum | alnum) >> !(alnum|'-')
] ];
This uses
lexeme
to handle whitespace significance,
raw
to avoid having to actively match every character that you want as part of the output (you just want all characters).
'-' >> alnum
positively mandates that any dash be followed by a alnum. Note this also outlaws "--"
in in the input. See VARIANT below
Live On Coliru
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <algorithm>
namespace x3 = boost::spirit::x3;
namespace parser {
using namespace boost::spirit::x3;
auto const rule = raw [ lexeme [
alnum >> *('-' >> alnum | alnum) >> !(alnum|'-')
] ];
}
int main() {
struct test { std::string input; bool expected; };
for (auto const t : {
test { "some-where", true },
test { " some-where", true },
test { "some-where ", true },
test { "s", true },
test { " s", true },
test { "s ", true },
test { "-", false },
test { " -", false },
test { "- ", false },
test { "some-", false },
test { " some-", false },
test { "some- ", false },
test { "some--where", false },
test { " some--where", false },
test { "some--where ", false },
})
{
std::string output;
bool ok = x3::phrase_parse(t.input.begin(), t.input.end(), parser::rule, x3::space, output);
if (ok != t.expected)
std::cout << "FAILURE: '" << t.input << "'\t" << std::boolalpha << ok << "\t'" << output << "'\n";
}
}
VARIANT
To also allow some--thing
and similar inputs, I'd change '-'
into +lit('-')
:
alnum >> *(+lit('-') >> alnum | alnum) >> !(alnum|'-')
Live On Coliru
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <algorithm>
namespace x3 = boost::spirit::x3;
namespace parser {
using namespace boost::spirit::x3;
auto const rule = raw [ lexeme [
alnum >> *(+lit('-') >> alnum | alnum) >> !(alnum|'-')
] ];
}
int main() {
struct test { std::string input; bool expected; };
for (auto const t : {
test { "some-where", true },
test { " some-where", true },
test { "some-where ", true },
test { "s", true },
test { " s", true },
test { "s ", true },
test { "-", false },
test { " -", false },
test { "- ", false },
test { "some-", false },
test { " some-", false },
test { "some- ", false },
test { "some--where", true },
test { " some--where", true },
test { "some--where ", true },
})
{
std::string output;
bool ok = x3::phrase_parse(t.input.begin(), t.input.end(), parser::rule, x3::space, output);
if (ok != t.expected)
std::cout << "FAILURE: '" << t.input << "'\t" << std::boolalpha << ok << "\t'" << output << "'\n";
}
}