Обратный смещенный токенизатор - PullRequest
1 голос
/ 13 ноября 2008

У меня есть строка для токенизации. Это форма HHmmssff, где H, m, s, f - цифры.

Он должен быть разбит на четыре двузначных числа, но мне нужно, чтобы он также принимал сокращенные формы, например sff, поэтому он интерпретируется как 00000sff. Я хотел использовать boost::tokenizer offset_separator, но, похоже, он работает только с положительными смещениями, и мне бы хотелось, чтобы это работало в обратном направлении.

Хорошо, одна идея состоит в том, чтобы дополнить строку нулями слева, но, возможно, сообщество придумает что-нибудь uber -сумное. ;)

Редактировать: Дополнительные требования только что вступили в игру.

Основная потребность в более разумном решении состояла в том, чтобы обрабатывать все случаи, такие как f, ssff, mssff и т. Д., Но также принимать более полные записи времени, такие как HH:mm:ss:ff с его сокращенными формами. например, s:ff или даже s: (этот должен интерпретироваться как s:00).

В случае, когда строка заканчивается на : Я, очевидно, могу также заполнить ее двумя нулями, затем удалить все разделители, оставив только цифры, и проанализировать полученную строку с помощью Spirit.

Но, похоже, было бы немного проще, если бы был способ заставить токенизатор смещения возвращаться назад от конца строки (смещения -2, -4, -6, -8) и лексически приводить числа к int s.

Ответы [ 3 ]

1 голос
/ 13 ноября 2008

Я продолжаю проповедовать нотацию БНФ. Если вы можете записать грамматику, которая определяет вашу проблему, вы можете легко преобразовать ее в анализатор Boost.Spirit, который сделает это за вас.

TimeString := LongNotation | ShortNotation

LongNotation := Hours Minutes Seconds Fractions

Hours := digit digit
Minutes := digit digit
Seconds := digit digit
Fraction := digit digit

ShortNotation := ShortSeconds Fraction
ShortSeconds := digit

Редактировать: дополнительное ограничение

VerboseNotation = [ [ [ Hours ':' ] Minutes ':' ] Seconds ':' ]  Fraction
0 голосов
/ 13 ноября 2008

В ответ на комментарий «Не хочу быть фанатом производительности, но это решение предполагает некоторое копирование строки (входные данные - это const & std :: string)».

Если вы действительно так сильно заботитесь о производительности, что не можете использовать большую старую библиотеку, такую ​​как regex, не рискуете анализатором BNF, не думайте, что std :: string :: substr позволит избежать копирования с распределением (и, следовательно, не может использовать строковые функции STL), и даже не может скопировать строковые символы в буфер и левую панель с символами '0':

void parse(const string &s) {
    string::const_iterator current = s.begin();
    int HH = 0;
    int mm = 0;
    int ss = 0;
    int ff = 0;
    switch(s.size()) {
        case 8:
            HH = (*(current++) - '0') * 10;
        case 7:
            HH += (*(current++) - '0');
        case 6:
            mm = (*(current++) - '0') * 10;
        // ... you get the idea.
        case 1:
            ff += (*current - '0');
        case 0: break;
        default: throw logic_error("invalid date");
        // except that this code goes so badly wrong if the input isn't
        // valid that there's not much point objecting to the length...
   }
}

Но, по сути, простая 0-инициализация этих переменных int - это почти такая же работа, как копирование строки в буфер символов с заполнением, так что я не ожидаю увидеть существенную разницу в производительности. Поэтому я не рекомендую это решение в реальной жизни, как упражнение по преждевременной оптимизации.

0 голосов
/ 13 ноября 2008

Регулярные выражения приходят на ум. Что-то вроде "^0*?(\\d?\\d?)(\\d?\\d?)(\\d?\\d?)(\\d?\\d?)$" с boost::regex. Submatches предоставит вам значения цифр. Не должно быть трудным принять другой формат с двоеточиями между числами (см. Ответ на sep61.myopenid.com). boost::regex - один из самых быстрых парсеров регулярных выражений.

...