Как мне выполнить это сопоставление с шаблоном текста - PullRequest
4 голосов
/ 10 ноября 2011

Перенесено из списка [ Духовный генерал ]

Доброе утро,

Я пытаюсь разобрать относительно простой шаблон по 4 std::strings, извлекая любую часть, которая соответствует шаблону, в отдельный std::string.

В отвлеченном смысле, вот что я хочу:

s1=<string1><consecutive number>, s2=<consecutive number><string2>,
s3=<string1><consecutive number>, s4=<consecutive number><string2>

Менее абстрактно:

s1="apple 1", s2="2 cheese", s3="apple 3", s4="4 cheese"

Фактическое содержание:

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"

Как мне выполнить сопоставление с этим шаблоном?

Спасибо за все предложения,

Алек Тейлор

Обновление 2

Вот очень простое объяснение, которое я только что выяснил, чтобы объяснить проблему, которую пытаюсь решить:

 std::string s1=garbagetext1+number1+name1+garbagetext4;
 std::string s3=garbagetext2+(number1+2)+name1+garbagetext5;
 std::string s5=garbagetext3+(number1+4)+name1+garbagetext6;

Редактировать для контекста:

Не стесняйтесь добавлять его вstackoverflow (у меня были некоторые проблемы с публикацией там)

Я не могу дать вам то, что я сделал до сих пор, потому что я не был уверен, что это было в пределах возможностейповышения :: spiбиблиотеки rit, чтобы делать то, что я пытаюсь сделать

Ответы [ 3 ]

4 голосов
/ 10 ноября 2011

Редактировать : 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

Две ноты:

  1. Добавьте (...)+ вокруг хвостовой части, чтобы позволить повторять совпадение узоров

      (\d+) ([a-z]+)(.*?(\d+) \2)+
    
  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;
}
2 голосов
/ 11 ноября 2011

При условии, что вы можете использовать компилятор c ++ 11, анализ этих шаблонов довольно прост с использованием AX :

#include <axe.h>
#include <string>

template<class I>
void num_value(I i1, I i2)
{
    unsigned n;
    unsigned next = 1;
    // rule to match unsigned decimal number and compare it with another number
    auto num = axe::r_udecimal(n) & axe::r_bool([&](...){ return n == next; });
    // rule to match a single word
    auto word = axe::r_alphastr();
    // rule to match space characters
    auto space = axe::r_any(" \t\n");

    // semantic action - print to cout and increment next
    auto e_cout = axe::e_ref([&](I i1, I i2) 
    { 
        std::cout << std::string(i1, i2) << '\n'; 
        ++next; 
    });

    // there are only two patterns in this example
    auto pattern1 = (word & +space & num) >> e_cout;
    auto pattern2 = (num & +space & word) >> e_cout;

    auto s1 = axe::r_find(pattern1);
    auto s2 = axe::r_find(pattern2);
    auto text = s1 & s2 & s1 & s2 & axe::r_end();
    text(i1, i2);
}

Для разбора текста просто вызовите num_value(text.begin(), text.end()); Никаких изменений не требуетсядля анализа строк в кодировке Unicode.

Я не проверял это.

0 голосов
/ 10 ноября 2011

Загляните в Boost.Regex.Я видел почти идентичный poosting в boost-пользователях, и решение состоит в том, чтобы использовать регулярные выражения для некоторых совпадений.

...