Vorrei analizzare una frase in cui alcune stringhe potrebbero non essere quotate, "quotate" o "quotate". Il codice sottostante funziona quasi, ma non riesce a far corrispondere le virgolette di chiusura. Suppongo che questo sia dovuto al riferimento qq. Una modifica è commentata nel codice, la modifica riporta in "quotato" o "quotato" anche l'analisi e aiuta a mostrare il problema originale è con la citazione di chiusura. Il codice descrive anche la grammatica esatta.Stringhe tra virgolette con boost: spirit
Per essere completamente chiari: analisi stringhe non quotate. Una stringa quotata come 'hello'
analizzerà la citazione aperta '
, tutti i caratteri hello
, ma non riuscirà a analizzare la citazione finale '
.
Ho fatto un altro tentativo, simile al tag di inizio/fine corrispondenza nello boost tutorials, ma senza successo.
template <typename Iterator>
struct test_parser : qi::grammar<Iterator, dectest::Test(), ascii::space_type>
{
test_parser()
:
test_parser::base_type(test, "test")
{
using qi::fail;
using qi::on_error;
using qi::lit;
using qi::lexeme;
using ascii::char_;
using qi::repeat;
using namespace qi::labels;
using boost::phoenix::construct;
using boost::phoenix::at_c;
using boost::phoenix::push_back;
using boost::phoenix::val;
using boost::phoenix::ref;
using qi::space;
char qq;
arrow = lit("->");
open_quote = (char_('\'') | char_('"')) [ref(qq) = _1]; // Remember what the opening quote was
close_quote = lit(val(qq)); // Close must match the open
// close_quote = (char_('\'') | char_('"')); // Enable this line to get code 'almost' working
quoted_string =
open_quote
>> +ascii::alnum
>> close_quote;
unquoted_string %= +ascii::alnum;
any_string %= (quoted_string | unquoted_string);
test =
unquoted_string [at_c<0>(_val) = _1]
> unquoted_string [at_c<1>(_val) = _1]
> repeat(1,3)[any_string] [at_c<2>(_val) = _1]
> arrow
> any_string [at_c<3>(_val) = _1]
;
// .. <snip>set rule names
on_error<fail>(/* <snip> */);
// debug rules
}
qi::rule<Iterator> arrow;
qi::rule<Iterator> open_quote;
qi::rule<Iterator> close_quote;
qi::rule<Iterator, std::string()> quoted_string;
qi::rule<Iterator, std::string()> unquoted_string;
qi::rule<Iterator, std::string()> any_string; // A quoted or unquoted string
qi::rule<Iterator, dectest::Test(), ascii::space_type> test;
};
// main()
// This example should fail at the very end
// (ie not parse "str3' because of the mismatched quote
// However, it fails to parse the closing quote of str1
typedef boost::tuple<string, string, vector<string>, string> DataT;
DataT data;
std::string str("addx001 add 'str1' \"str2\" -> \"str3'");
std::string::const_iterator iter = str.begin();
const std::string::const_iterator end = str.end();
bool r = phrase_parse(iter, end, grammar, boost::spirit::ascii::space, data);
Per il credito bonus: una soluzione che evita un membro di dati locale (come char qq
nell'esempio sopra) sarebbe preferibile, ma da un punto di vista pratico userò tutto ciò che funziona!
Per la cronaca, rendendo 'char qq' una variabile membro della' struct test_parser' non esattamente nello stesso modo. – Zero
Non riesce a "nello stesso modo?" Non ci hai detto come questo fallisce (anche se posso immaginarlo è dovuto al riferimento a 'qq'). –
@NicolBolas È stato un commento nel codice: ho chiarito la domanda, grazie per averlo indicato.Sospetto anche il ref (qq), ma il lato negativo di boost lambda & co è che sono difficili da eseguire il debug in quanto non è possibile passare attraverso il senso tradizionale! – Zero