0

I need to parse string with parameters A and B. Order of the parameters not defined. I.e. string can be present as one of the next formats

A="value1",B="value2"
B="value1",A="value2"

Part of my code you can see below. But in that code I can parse only A="value1",B="value2" variant. Could I modify this code to parse the first and second variants together? Yes, I can add alternative condition ("|"). But what if I need to parse new C and D parameters.

using Iterator = std::string::const_iterator;
qi::rule<Iterator, std::string()> quotedStringParser;
quotedStringParser %= ('"' >> +(qi::char_ - '"') >> '"');

std::string A;
std::string B;
bool isImport = false;

if (!qi::parse(begin(line), end(line),
    ("A=" >> quotedStringParser[px::ref(A) = qi::_1] >> ',' >> "B=" >> quotedStringParser[px::ref(B) = qi::_1]) >> qi::eoi
)) {
    return false;
}
  • I just *know* this is in relation to https://stackoverflow.com/questions/68174743/boostspiritqi-extract-parameters-values-from-the-line. I haven't found the courage to address that question: Please **don't** do it the convoluted way. Just separate your concerns. Parse *syntax** top-down, do semantic validation after scanning/parsing. – sehe Jul 01 '21 at 11:04
  • 1
    That's how the grammar has been designed to even be extensible and it makes your code faster, easier to maintain, much less error prone (see e.g. https://stackoverflow.com/questions/67873608/how-to-parse-rtsp-url-with-boost-qi/67879179#67879179 vs. https://stackoverflow.com/questions/2958747/what-is-the-nicest-way-to-parse-this-in-c/66827620#66827620). Oh and it will likely compile a ton faster. – sehe Jul 01 '21 at 11:04
  • That all said, there is [`operator^`](https://www.boost.org/doc/libs/1_76_0/libs/spirit/doc/html/spirit/qi/reference/operator/permutation.html) - I have several answers showing that kind of approach on this site, but sadly search is so bad at finding those... Update using "permuation" as search keyword helped: https://stackoverflow.com/search?q=user%3A85371+permutation+qi Maybe google has even better results. – sehe Jul 01 '21 at 11:27
  • 2
    Hello @sehe, yes you right. Questions is related. I removed the old question. Finally, I parsed all arguments to std::map, and wrote logic for attributes additional checking. – Валентин Никин Jul 02 '21 at 05:46

1 Answers1

2

Since you want to be able to extend this to an arbitrary number of parameters, it would be easier to treat this as a comma-delimited list of alternatives, each with a semantic action. This way, you don't have to deal with all possible permutations.

(("A=" >> quotedStringParser[px::ref(A) = qi::_1]) | 
 ("B=" >> quotedStringParser[px::ref(B) = qi::_1]) |
 ("C=" >> quotedStringParser[px::ref(C) = qi::_1]) |
 ("D=" >> quotedStringParser[px::ref(D) = qi::_1]) ) % "," >> qi::eoi

This is, however, a very tolerant parser.

  • It's acceptable to not set all values
  • It's possible to reassign the same value multiple times.

If you want to maintain the same level of strictness you had, it's all stuff that you can validate post-parsing with relative ease.

  • Thank you for the reply. You say "it's all stuff that you can validate post-parsing with relative ease.". Could you please explain me, how I can do it? I'm newest in boost, so I haven't idea, how I can do it. – Валентин Никин Jul 01 '21 at 08:14
  • It's basically the same thing as @sehe is saying to with regards to *separation of concerns*. If you care about making sure A,B,C, and D are all set, don't do it as part of the parser. Just check that they all have values after parsing is done. –  Jul 01 '21 at 12:03
  • 1
    @ВалентинНикин Also, and this is more of a matter of opinion (hence why it's not part of the answer), in your shoes, I would parse a `std::map>` and do the assignment to A,B,C,D after parsing is done. That would compile a lot faster, and would scale to an arbitrary number of keys for "free". –  Jul 01 '21 at 12:08