Нужно разобрать строку, имеющую маску (что-то вроде этого "% yr-% mh-% dy"), поэтому я получаю значения int - PullRequest
2 голосов
/ 25 августа 2009

Например, мне нужно найти время в формате, указанном в заголовке (но порядок тегов % может отличаться) в строке "The date is 2009-August-25." Как мне заставить программу интерпретировать теги и какую конструкцию лучше использовать для хранения их вместе с информацией о том, как действовать с определенными частями строки даты?

Ответы [ 2 ]

1 голос
/ 26 августа 2009

Сначала загляните в библиотеку boost::date_time. Он имеет систему ввода-вывода , которая может быть тем, что вы хотите, но я вижу отсутствие поиска.

Для пользовательского поиска по дате вам нужно boost::xpressive. Он содержит все, что вам нужно. Давайте посмотрим на мой наспех написанный пример. Сначала вы должны разобрать свой собственный шаблон, ведь с Xpressive это просто. Сначала посмотрите на заголовок, который вам нужен:

#include <string>
#include <iostream>
#include <map>
#include <boost/xpressive/xpressive_static.hpp>
#include <boost/xpressive/regex_actions.hpp>

//make example shorter but less clear
using namespace boost::xpressive;

Второе определение карты ваших специальных тегов:

std::map<std::string, int > number_map;
number_map["%yr"] = 0;
number_map["%mh"] = 1;
number_map["%dy"] = 2;
number_map["%%"] = 3;  // escape a %

Следующий шаг - создание регулярного выражения, которое будет анализировать наш шаблон с тегами и сохранять значения из карты в переменную tag_id, когда найдет тег, или сохранить -1 в противном случае:

int tag_id;
sregex rx=((a1=number_map)|(s1=+~as_xpr('%')))[ref(tag_id)=(a1|-1)];

Более подробную информацию и описание смотрите здесь и здесь . Теперь давайте разберем некоторый шаблон:

  std::string pattern("%yr-%mh-%dy"); // this will be parsed

  sregex_token_iterator begin( pattern.begin(), pattern.end(), rx ), end;
  if(begin == end) throw std::runtime_error("The pattern is empty!");

sregex_token_iterator будет перебирать наши токены и каждый раз устанавливать переменную tag_id. Все, что нам нужно сделать, это создать регулярное выражение, используя эти токены. Мы построим это регулярное выражение, используя теги соответствующие части статического регулярного выражения, определенного в массиве:

sregex regex_group[] = {
    range('1','9') >> repeat<3,3>( _d ), // 4 digit year
    as_xpr( "January" ) | "February" | "August", // not all month XD so lazy
    repeat<2,2>( range('0','9') )[    // two digit day
    check(as<int>(_) >= 1 && as<int>(_) <= 31) ], //only bettwen 1 and 31
    as_xpr( '%' )  // match escaped %
};

Наконец, давайте начнем строить наше специальное регулярное выражение. Первый матч построит первую его часть. Если тег совпадает и tag_id неотрицателен, мы выбираем регулярное выражение из массива, иначе совпадение, вероятно, является разделителем, и мы создаем регулярное выражение, которое соответствует ему:

sregex custom_regex = (tag_id>=0) ? regex_group[tag_id] : as_xpr(begin->str());

Далее мы будем перебирать от начала до конца и добавлять следующее регулярное выражение:

while(++begin != end)
{
    if(tag_id>=0)
    {
        sregex nextregex = custom_regex >> regex_group[tag_id];
        custom_regex = nextregex;
    }
    else
    {
        sregex nextregex = custom_regex >> as_xpr(begin->str());
        custom_regex = nextregex;
    }
}

Теперь наше регулярное выражение готово, давайте найдем несколько дат: -]

std::string input = "The date is 2009-August-25.";

smatch mydate;
if( regex_search( input, mydate, custom_regex ) )
    std::cout << "Found " << mydate.str() << "." << std::endl;

Библиотека xpressive очень мощная и быстрая. Это также красивое использование шаблонов.

Если вам нравится этот пример, дайте мне знать в комментариях или пунктах; -)

1 голос
/ 25 августа 2009

Я бы преобразовал помеченную строку в регулярное выражение с захватом для 3 полей и искал бы его. Сложность регулярного выражения будет зависеть от того, что вы хотите принять за% yr. Вы также можете иметь менее строгое выражение и затем проверять допустимые значения, это может привести к лучшим сообщениям об ошибках («Недопустимый месяц: Augsut» вместо «дата не найдена») или к ложным срабатываниям в зависимости от контекста.

...