Редактировать : Re Обновление2
Вот очень простое объяснение, которое я только что выяснил, чтобы объяснить
Проблема, которую я пытаюсь решить:
std::string s1=garbagetext1+number1+name1+garbagetext4;
std::string s3=garbagetext2+(number1+2)+name1+garbagetext5;
std::string s5=garbagetext3+(number1+4)+name1+garbagetext6;
Это начинает выглядеть как работа для:
- Маркировка «мусорного текста / имен» - вы можете создать на лету таблицу символов и использовать ее для сопоставления с образцами (дух Лекса и таблица символов Ци (
qi::symbol
) могут облегчить это, но я чувствую, что вы могли бы напишите это любым количеством способов)
- и наоборот, используйте регулярные выражения, как предлагалось ранее ( ниже и, по крайней мере, дважды в списке рассылки).
Вот простая идея:
(\d+) ([a-z]+).*?(\d+) \2
\d+
соответствует последовательности цифр в "( подвыражении )" (NUM1
)
([a-z]+)
соответствует имени (только что выбрано простое определение «имени»)
.*?
пропустить мусор любой длины, но как можно меньше перед началом следующего матча
\d+
соответствует другому номеру (последовательность цифр) (NUM2
)
\2
, за которым следует то же имя ( обратная ссылка )
Вы можете видеть, как вы уже сужаете список совпадений, чтобы проверять вплоть до «потенциальных» попаданий. Вам нужно только / пост-проверить / чтобы увидеть, что NUM2 == NUM1 + 2
Две ноты:
Добавьте (...)+
вокруг хвостовой части, чтобы позволить повторять совпадение узоров
(\d+) ([a-z]+)(.*?(\d+) \2)+
Возможно, вы захотите, чтобы пропуск мусора (.*?
) учитывал разделители (выполняя отрицательные утверждения нулевой ширины ), чтобы избежать более 2 пропускающих разделителей (например, s\d+="
как шаблон разграничения). Я оставляю это вне поля зрения для ясности, вот суть:
((?!s\d+=").)*? -- beware of potential performance degradation
Алек, Ниже приведена демонстрация того, как делать широкий круг вещей в Boost Spirit, в контексте ответа на ваш вопрос.
Мне пришлось сделать предположения о том, какая требуется структура ввода; Я предположил
- пробел был строгим (пробелы, как показано, без перевода строки)
- порядковые номера должны быть в порядке возрастания
- порядковые номера должны повторяться точно в текстовых значениях
- ключевые слова 'яблоко' и 'сыр' находятся в строгом чередовании
- указывается ли ключевое слово 1105 * перед или после порядкового номера в текстовом значении, также строго чередуя
Примечание В приведенной ниже реализации есть около дюжины мест, где можно было бы сделать значительно менее сложный выбор. Например, я мог бы жестко закодировать весь шаблон (как de facto regex ?), Предполагая, что во входных данных всегда ожидаются 4 элемента. Однако я хотел
Однако решение обеспечивает большую гибкость:
- ключевые слова не жестко закодированы, и вы можете, например, легко заставить парсер принимать оба ключевых слова с любым порядковым номером
- комментарий показывает, как генерировать пользовательское исключение при разборе, когда порядковый номер не синхронизирован (не ожидаемое число)
- в настоящее время принимаются различные варианты написания порядковых номеров (т.е.
s01="apple 001"
в порядке. Посмотрите на Unsigned Integer Parsers для получения информации о том, как настроить это поведение)
выходная структура является либо vector<std::pair<int, std::string> >
, либо вектором структуры:
struct Entry
{
int sequence;
std::string text;
};
обе версии могут переключаться с помощью одной #if 1/0
линии
В примере используется Boost Spirit Qi для анализа.
И наоборот, Boost Spirit Karma используется для отображения результата анализа:
format((('s' << auto_ << "=\"" << auto_) << "\"") % ", ", parsed)
Вывод для фактического содержания , приведенный в сообщении:
parsed: s1="apple 1", s2="2 cheese", s3="apple 3", s4="4 cheese"
Включение в код.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
#if 1 // using fusion adapted struct
#include <boost/fusion/adapted/struct.hpp>
struct Entry
{
int sequence;
std::string text;
};
BOOST_FUSION_ADAPT_STRUCT(Entry, (int, sequence)(std::string, text));
#else // using boring std::pair
#include <boost/fusion/adapted/std_pair.hpp> // for karma output generation
typedef std::pair<int, std::string> Entry;
#endif
int main()
{
std::string input =
"s1=\"lxckvjlxcjvlkjlkje xvcjxzlvcj wqrej lxvcjz ljvl;x czvouzxvcu"
"j;ljfds apple 1 xcvljxclvjx oueroi xcvzlkjv; zjx\", s2=\"xzljlkxvc"
"jlkjxzvl jxcvljzx lvjlkj wre 2 cheese\", s3=\"apple 3\", s4=\"kxclvj"
"xcvjlxk jcvljxlck jxcvl 4 cheese\"";
using namespace qi;
typedef std::string::const_iterator It;
It f(input.begin()), l(input.end());
int next = 1;
qi::rule<It, std::string(int)> label;
qi::rule<It, std::string(int)> value;
qi::rule<It, int()> number;
qi::rule<It, Entry(), qi::locals<int> > assign;
label %= qi::raw [
( eps(qi::_r1 % 2) >> qi::string("apple ") > qi::uint_(qi::_r1) )
| qi::uint_(qi::_r1) > qi::string(" cheese")
];
value %= '"'
>> qi::omit[ *(~qi::char_('"') - label(qi::_r1)) ]
>> label(qi::_r1)
>> qi::omit[ *(~qi::char_('"')) ]
>> '"';
number %= qi::uint_(phx::ref(next)++) /*| eps [ phx::throw_(std::runtime_error("Sequence number out of sync")) ] */;
assign %= 's' > number[ qi::_a = _1 ] > '=' > value(qi::_a);
std::vector<Entry> parsed;
bool ok = false;
try
{
ok = parse(f, l, assign % ", ", parsed);
if (ok)
{
using namespace karma;
std::cout << "parsed:\t" << format((('s' << auto_ << "=\"" << auto_) << "\"") % ", ", parsed) << std::endl;
}
} catch(qi::expectation_failure<It>& e)
{
std::cerr << "Expectation failed: " << e.what() << " '" << std::string(e.first, e.last) << "'" << std::endl;
} catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
if (!ok || (f!=l))
std::cerr << "problem at: '" << std::string(f,l) << "'" << std::endl;
}