SRC: boost::(spirit|regex) для бедных
От: TepMuHyc  
Дата: 13.11.03 17:25
Оценка: 254 (24)
...Работы у меня сегодня не было, а настроение поизвращаться с C++ — было.
В результате всего этого, появился "шедевер" — шаблонная библиотека статических регулярных выражений, в чем-то смахивающая на SPIRIT. Вот только она гаараздо меньше — всего 7 килобайт. Ну, и гораздо примитивнее, конечно.

Основная ее фишка в том, что компиляция регулярного выражения проводится на этапе компиляции программы — прямо в исполнимый код (довольно страшноватенький — т.к. оптимизация еще впереди). А на этапе выполнения остается только пользоваться функцией поиска совпадений...

пример:
//задаем регулярное выражение (обьяснение примитивов будет ниже)
namespace myrx
{
    using namespace rx_tmpl;
    
    typedef //определяем регулярное выражение для выделения числа 
            //с плавающей точкой: [+-]?[0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)? 
        seq<
            opt<set<'+','-'> >,
            plus<digit>,
            opt<seq<c<'.'>, plus<digit> > >,
            opt<seq<set<'E','e'>, opt<set<'+','-'> >, plus<digit> > >
        >
    float_num;
}

//применяем его...
void function()
{
    string number("123.45E-56 some text");
    string::iterator it = number.begin();
    if( myrx::float_num::match(it, number.end()) )
    {
        //строка совпала.
        //итератор it указывает на позицию сразу за числом
    } else {
        //строка не совпала
        //позиция итератора не изменилась.
    }
}


примитивы:
c<'A'> - литеральный символ.
s<'H','E','L','L','O'> - литеральная строка
set<'A','B','C','D','E','F'> - набор символов - как [ABCDEF].
range<'A','Z'> - диапазон символов - как [A-Z].
range<'A','Z',false> - диапазон символов - как [^A-Z].
ws - пробел или таб [ \t]
digit - цифра - как [0-9]
alpha - английская буква без учета регистра - как [A-Za-z]
star<RX> - ноль или более совпадений - как (abcd)*
plus<RX> - одно или более или более совпадений - как (abcd)+
opt<RX> - необязательное совпадение - как (abcd)?
alt<RX1,RX2> - альтернатива - как (abc|def)
seq<RX1,RX2,RX3,....,RX10> - конкатенация регулярных выражений


ЗЫ. Код будет в следующем сообщении в этой же нитке.
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: Код: версия 0.00000003 - бенчмарки
От: TepMuHyc  
Дата: 25.11.03 18:59
Оценка: 29 (2)
...запустил нижеприведенную програмку и просто офигел...
Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько
# matches: 60000 # fails: 40000
my time: 40

# matches: 60000 # fails: 40000
boost time: 3055


Вот исходники тестовой программы.
Проверялось на VC 7.1 с ключом /O2.

#define BOOST_REGEX_STATIC_LINK
#include <windows.h>
#include <string>
#include <iostream>
#include "../static_regex.h"
#include <boost/regex.hpp>

using std::string;
namespace
{
    using namespace static_regex;
    typedef 
    seq<
        select< plus<digit> >,               //код ответа
        select< alt<cc<'-',' '>, endl> >,    //символ переноса - если '-' - то ответ многострочный
        select< star<not_cc<'\r','\n'> > >,  //текст сообщения - все до конца строки
        opt<endl>                            //необязательный перевод строки
    > 
    rx_ftp;

    boost::regex brx_ftp("([0-9]+)([\\- ]|(?:\r?\n))([^\r\n]*)(?:\r?\n)?");
}

string data[] = {
    "202Slightly malformed response\r\n",
    "200 Hello beutiful world\n",
    "201-Hello nice and beutiful world\n",
    "202-Hello sometimes nice and beutiful but mostly ugly world\r\n",
    "Not a response at all\r\n",
};

bool is_ftpanswer(const string& data)
{
    int nsubm;
    string::const_iterator subm[2*10];

    if( rx_ftp::match(data.begin(),data.end(),subm,nsubm=0) )
    {
        return true;
    }
    return false;
}

bool bis_ftpanswer(const string& data)
{
   boost::smatch what;
   if( boost::regex_match(data, what, brx_ftp) )
   {
      return true;
   }
   return false;
}

int main()
{
    DWORD start=0;
    int nmatches, nfails;
    const int NITER = 20000;

    nmatches = nfails = 0;
    start = GetTickCount();
    for(int i=0; i < NITER; i++ )
    {
        for( int r=0; r<5; r++ )
             is_ftpanswer( data[r] )
                ? ++nmatches : ++nfails;
    }
    std::cout << "# matches: " << nmatches << " # fails: " << nfails << std::endl;
    std::cout << "my time: " << (GetTickCount() - start) << std::endl;

    nmatches = nfails = 0;
    start = GetTickCount();
    for(int i=0; i < NITER; i++ )
    {
        for( int r=0; r<5; r++ )
             bis_ftpanswer( data[r] )
                ? ++nmatches : ++nfails;
    }
    std::cout << "# matches: " << nmatches << " # fails: " << nfails << std::endl;
    std::cout << "boost time: " << (GetTickCount() - start) << std::endl;
}
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[4]: SRC: boost::(spirit|regex) для бедных
От: TepMuHyc  
Дата: 14.11.03 13:05
Оценка: 6 (1) -1
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>а чо, давай сгенерируем что мешает-то?


Если ты настолько кррррутттт, go ahead — генери.
А я данную тему знаю не понаслышке — даже сгенерить голый NFA по Тейлору — задачка далеко нетривиальная.
Причем, получим совершенно неоптимальное представление — в виде графа на указателях и (что самое подлое) без оптимизации e-closure(char).

И, если все же каким-то чудом удастся — исходников будет — дайбожЕ уместиться килобайт в 100
А компилироваться они будут... успеешь поесть, трахнуть жену, выспаться — и далее по циклу раз 5

TMH>>Что же касается скорости, то моя билиотека будет слабже boost::regex как минимум в несколько раз. И только некоторые специально оптимизированные регулярные выражения могут позволить им сравниться в скорости.


ЗХ>а чем это обусловлено?

Я же говорил чем — одни и те же участки строки могут просматриваться несколько раз — особенно этим грешит примитив alt<>.
boost::regex (да и любая себя уважающая библиотека рег.выражений) разбор строки делает за один проход.

TMH>>В целом, я бы рекомендовал применять мою библотеку когда:

TMH>>1) Количество рег.выражений малО — не более 10-20.
TMH>>2) Все они известны на compile-time
TMH>>3) Скорость выполнения поиска совпадений не критична и/или рег.выражения достаточно простЫ.

ЗХ>в этих условиях она будет лучше, чем regex?

Да — хотя бы по времени компиляции и размеру кода.
Что же касается скорости, то как известно, 20% от кода программы исполняются 80% времени жизни программы.
Надо только следить чтобы в эти 20% не попали функции rx_templ::some_regex::match()
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re: Код: версия 0.00000001
От: TepMuHyc  
Дата: 13.11.03 17:30
Оценка: 15 (1)
Проверено и работает:
— VC 6.0SP5 и старше
— Mingw GCC 3.3.1

#include <stdio.h>
#include <algorithm>

namespace rx_tmpl
{
    namespace impl
    {
        template<wchar_t E, class TAIL>
        struct strn: TAIL
        {
            template<class InIt>
            static bool match(InIt& it, const InIt& end)
            {
                return (it != end) && (E == *it) && TAIL::match(++it,end);
            }
        };

        struct strnlast
        {
            template<class InIt>
            static bool match(InIt& it, const InIt& end)
            {
                return true;
            }
        };

        template<wchar_t E, class TAIL>
        struct setn: TAIL
        {
            static bool do_match(wchar_t ch)
            {
                return (E == ch) || TAIL::do_match(ch);
            }
        };

        struct setnlast
        {
            static bool do_match(wchar_t ch)
            {
                return false;
            }
        };


        template<class RX, class TAIL>
        struct seqn: TAIL
        {
            template<class InIt>
            static bool do_match(InIt& it, const InIt& end)
            {
                return RX::match(it,end) && TAIL::do_match(it,end);
            }
        };

        struct seqnlast
        {
            template<class InIt>
            static bool do_match(InIt& it, const InIt& end)
            {
                return true;
            }
        };
    }//namespace impl

template<wchar_t E>
struct c /* literal charachter */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (E == *it);
        if( res ) ++it;
        return res;
    }
};

template<
int c0,     int c1,     int c2 =-1, int c3 =-1, int c4 =-1, int c5 =-1, int c6 =-1, int c7 =-1, int c8 =-1, int c9 =-1,
int c10=-1, int c11=-1, int c12=-1, int c13=-1, int c14=-1, int c15=-1, int c16=-1, int c17=-1, int c18=-1, int c19=-1,
int c20=-1, int c21=-1, int c22=-1, int c23=-1, int c24=-1, int c25=-1, int c26=-1, int c27=-1, int c28=-1, int c29=-1
>
struct s /* literal string - up to 30 symbols */
    :impl::strn<
        c0,
        s<
            c1,c2,c3,c4,c5,c6,c7,c8,c9,
            c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,
            c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,
            -1
        >
    >
{};

template<> 
struct s<
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1>
:impl::strnlast
{};

template<
int c0,     int c1,     int c2 =-1, int c3 =-1, int c4 =-1, int c5 =-1, int c6 =-1, int c7 =-1, int c8 =-1, int c9 =-1,
int c10=-1, int c11=-1, int c12=-1, int c13=-1, int c14=-1, int c15=-1, int c16=-1, int c17=-1, int c18=-1, int c19=-1,
int c20=-1, int c21=-1, int c22=-1, int c23=-1, int c24=-1, int c25=-1, int c26=-1, int c27=-1, int c28=-1, int c29=-1
>
struct set /* charachter set - up to 30 chars - like "[ABCDEFabcdef]"*/
{
    typedef impl::setn<
        c0,
        typename set<
            c1,c2,c3,c4,c5,c6,c7,c8,c9,
            c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,
            c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,
            -1
        >::node
    > node;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && node::do_match(*it);
        if( res ) ++it;
        return res;
    }
};

template<> 
struct set<
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1>
{
    typedef impl::setnlast node;
};

template<wchar_t FRONT, wchar_t BACK, bool INCLUSIVE=true>
struct range /*charachter range - like "[a-d]" or "[^a-d]" */
{
    template<bool> struct sel {};
    //PXT_CASSERT((FRONT < BACK));

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, sel<true>)
    {
        bool res = (it != end) && (FRONT >= *it) && (*it <= BACK);
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, sel<false>)
    {
        return !do_match(it, end, sel<true>());
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return do_match(it, end, sel<INCLUSIVE>());
    }
};

struct ws /* whitespace chars */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && ((*it == ' ') || (*it == '\t'));
        if( res ) ++it;
        return res;
    }
};

struct digit /* numeric chars */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (*it >= '0') && (*it <= '9');
        if( res ) ++it;
        return res;
    }
};

struct alpha /* numeric chars */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (
            ((*it >= 'A') && (*it <= 'Z')) || 
            ((*it >= 'a') && (*it <= 'z'))
        );
        if( res ) ++it;
        return res;
    }
};

template<class RX>
struct star /*zero or more occurences of RX - like "(abc)*" */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        while( true )
        {
            InIt t(it);
            if( false == RX::match(it, end) || it == t )
                break;
        }
        return true;
    }
};

template<class RX>
struct plus /*one or more occurences of RX - like "(abc)+" */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end) && star<RX>::match(it, end);
    }
};

template<class RX>
struct opt /*optional occurence of RX - like "(abc)?" */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        RX::match(it, end);
        return true;
    }
};

template<class RX1, class RX2>
struct alt /*alternative - like "(abc|def)" */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt i1(it); bool b1 = RX1::match(i1,end);
        InIt i2(it); bool b2 = RX2::match(i2,end);
        if( b1 && b2 )
            it = (std::max)(i1,i2);
        else if( b1 )
            it = i1;
        else if( b2 )
            it = i2;
        else
            return false;
        return true;
    }
};

struct seqe {};
template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe, 
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe
>
struct seq 
{
    typedef impl::seqn<
        RX0,
        typename seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe>::node
    > node;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt t(it);
        bool res = node::do_match(it,end);
        if( !res ) it = t;
        return res;
    }
};

template<>
struct seq<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    typedef impl::seqnlast node;
};

}//namespace rx_tmpl

namespace myrx
{
    using namespace rx_tmpl;

    typedef 
        seq<
            s<'H','E','L','L','O'>,
            alt< c<','>, ws>,
            star<ws>,
            alt<
                seq<s<'R','E','G','E','X'>, opt< c<'P'> > >,
                seq<s<'R','E','G','U','L','A','R'>, plus<ws>, s<'E','X','P','R','E','S','S','I','O','N'> >
            >
        >
    rx;

    typedef 
        //{D}+(\.{D}+)?([Ee][+-]?{D}+)? 
        seq<
            opt<set<'+','-'> >,
            plus<digit>,
            opt<seq<c<'.'>, plus<digit> > >,
            opt<seq<set<'E','e'>, opt<set<'+','-'> >, plus<digit> > >
        >
    float_num;
}

template<class RX>
void test(char* pp)
{
    char* p = pp;
    bool res = RX::match(p, p+strlen(p));
    printf("\"%s\" %s matched\n", pp, res?"":"not");
}

int main()
{
    test<myrx::float_num>("123");
    test<myrx::float_num>("-123");
    test<myrx::float_num>("123.45");
    test<myrx::float_num>("123E-10");
    test<myrx::float_num>("123.45E-10");
    test<myrx::float_num>("+123.45E-10");
}
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: Код: версия 0.00000001
От: Кодт Россия  
Дата: 14.11.03 14:42
Оценка: 14 (1)
Здравствуйте, TepMuHyc, Вы писали:

А почему в качестве дефолтного символа в шаблонах использован -1 (русское "я"), а не 0 ?
Перекуём баги на фичи!
Re[3]: Код: версия 0.00000001
От: TepMuHyc  
Дата: 14.11.03 10:29
Оценка: 12 (1)
Здравствуйте, ArtDenis, Вы писали:

AD>Офигеть! Как же всё это работает???

Алямянтарно, Ватсон.

Регулярное выражение состоит из комбинации примитивов.
Каждый примитив определяет "функцию совпадения" следующего формата:
    template<class InIt>
    static bool match(InIt& it, const InIt& end);

Если совпадение найдено, match() возвращает true и продвигает итератор it на нужное количество символов. Если же совпадение не найдено, возвращается true и итератор остается в прежней позиции.

Собственно, для того чтобы класс стал "примитивом", все что ему необходимо — это реализовать функцию match(). То есть, "расширение и углубление" возможностей данной библиотеки — дело довольно простое.

Примитивы можно разделить на "терминальные" — это те, которые выполняют "реальную работу" — т.е. сравнение итератора в текущей позиции и символа — это шаблоны c<>, s<>, set<>, range<>, ws, alpha, digit,
И "нетерминальные" — которые выполняют логические операции над другими примитивами (как терминальными, так и нет) — это plus<>, star<>, opt<>, alt<>, seq<>.

В результате комбинирования терминальных примитивов при помощи нетерминальных, генерируется "функция совпадения" код которой представляет собой "дерево разбора" регулярного выражения. А выполнение этой функции — это как бы "обход" этого дерева разбора.

Что же касается реализации рекурсивных шаблонов set<> seq<> и s<>, то принцип их построения достаточно хорошо описан у Александреску — в главе про TypeList<>. Единственное, что можно в какой-то мере считать моим достижением в их реализации — удалось обойтись без частичной специализации (это важно для VC6.0) и сделать это достаточно красиво...

Кстати, о рекурсии: класс boost::tuple<> построен примерно на той же технологии, но имхо несколько более "некрасиво".
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: SRC: boost::(spirit|regex) для бедных
От: TepMuHyc  
Дата: 14.11.03 11:17
Оценка: 12 (1)
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>а вот такой вопрос — насколько это эффективнее (и эфективнее ли?) классического бустового варианта?

...Это второй человек, который захотел бенчмарок... Этакие вы ненасытные
Я ж этот код сотворил вчера за 4 часа на коленке

ЗХ>размер получившегося ехе-шника,

Тут надо учитывать количество уникальных регулярных выражений задействованных в программе.

На малом количестве выражений — моя библиотека будет выигрывать, причем на порядки — т.к. она генерит только функции поиска совпадений.
На большам количестве выражений — моя сначала сравняется, а потом начнет отставать.
Я ожидаю, что с boost::regex по размеру она сравнится при количестве рег.выражений около 100 или 200, но это надо проверять...

ЗХ>скорость выполнения,

boost::regex построена на недерминированном конечном автомате — что означает что она только один раз извлекает каждый элемент строки из итератора. Из этого, кстати, следует что она может использовать input_iterator — а это дорогого стОит.

Моя билиотека — это голый и примитивный обход дерева (увы, сгенерировать конечный автомат на шаблонах мне еще слабО ). Несколько спасает то, что этот обход выгоняется в исполнимый код.
Но "откаты назад" и повторные проверки участков последовательности неизбежны — в особенности этим страдает примитив alt<>. Так что, она может использовать только random_access_iterator. Я пробовал адаптировать ее к forward_iterator — получилось, но мне хочется именно input_iterator, поэтому я счел поддержку forward_iterator слишком обременительной и выкинул ее. (В принципе, у меня в башке бродит идея "кэширующего итератора", который мог бы превратить input_iterator в random_access_iterator, но это пока только идея и вопрос, надо ли ?)

Что же касается скорости, то моя билиотека будет слабже boost::regex как минимум в несколько раз. И только некоторые специально оптимизированные регулярные выражения могут позволить им сравниться в скорости.

ЗХ>простоту написания (ну тут явно налицо некоторый проигрыш, хотя, в принципе, можно привыкнуть)

Если привыкнуть, то просто — мне, например, очень просто

В целом, я бы рекомендовал применять мою библотеку когда:
1) Количество рег.выражений малО — не более нескольких 10-20.
2) Все они известны на compile-time
3) Скорость выполнения поиска совпадений не критична и/или рег.выражения достаточно простЫ.
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re: Re: Код: версия 0.00000002
От: TepMuHyc  
Дата: 14.11.03 13:39
Оценка: 9 (1)
Изменения:
— подчищен код — убраны ненужные наследования, реализация всех рекурсивных шаблонов приведена к единообразию
— убраны все реверансы в строну forward_iterator — библиотека теперь поддерживает ТОЛЬКО random_access_iterator
— примитив alt<> теперь поддерживает до 10 подвыражений (раньше только 2)
— оптимизирован примитив s<> — убраны ненужные проверки конца последовательности.

Планы на следующие версии:
— примитив select<RX> — выделение подвыражений — будут изменения формата функции match()
— терминальные примитивы нечувствительные к регистру букв — думаю как сделать максимально гибко (эх, где ты, template typedef)

namespace rx_tmpl
{
    namespace impl
    {
        template<wchar_t E, class TAIL>
        struct strn
        {
            enum{ length = 1 + TAIL::length };

            template<class InIt>
            static bool do_match(InIt& it)
            {
                return (E == *it) && TAIL::do_match(++it);
            }
        };

        struct strnlast
        {
            enum{ length = 0 };

            template<class InIt>
            static bool do_match(InIt& it)
            {
                return true;
            }
        };

        template<wchar_t E, class TAIL>
        struct setn
        {
            static bool do_match(wchar_t ch)
            {
                return (E == ch) || TAIL::do_match(ch);
            }
        };

        struct setnlast
        {
            static bool do_match(wchar_t ch)
            {
                return false;
            }
        };

        template<class RX, class TAIL>
        struct seqn
        {
            template<class InIt>
            static bool do_match(InIt& it, const InIt& end)
            {
                return RX::match(it,end) && TAIL::do_match(it,end);
            }
        };

        struct seqnlast
        {
            enum{ last = true };

            template<class InIt>
            static bool do_match(InIt& it, const InIt&)
            {
                return true;
            }
        };

        template<class RX, class TAIL>
        struct altn /*alternative - like "(abc|def)" */
        {
            template<bool> struct sel{};
            enum{ last = false };

            template<class InIt>
            static bool do_match(InIt& it, const InIt& end, sel<false>)
            {
                InIt i1(it); bool b1 = RX::match(i1,end);
                InIt i2(it); bool b2 = TAIL::do_match(i2,end);
                if( b1 && b2 )
                    it = (i1 < i2) ? i2 : i1;
                else if( b1 )
                    it = i1;
                else if( b2 )
                    it = i2;
                else
                    return false;
                return true;
            }

            template<class InIt>
            static bool do_match(InIt& it, const InIt& end, sel<true>)
            {
                return RX::match(it,end);
            }

            template<class InIt>
            static bool do_match(InIt& it, const InIt& end)
            {
                return do_match(it,end, sel<TAIL::last>());
            }
        };
    }//namespace impl

template<wchar_t E>
struct c /* literal charachter */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (E == *it);
        if( res ) ++it;
        return res;
    }
};

template<
int c0,     int c1,     int c2 =-1, int c3 =-1, int c4 =-1, int c5 =-1, int c6 =-1, int c7 =-1, int c8 =-1, int c9 =-1,
int c10=-1, int c11=-1, int c12=-1, int c13=-1, int c14=-1, int c15=-1, int c16=-1, int c17=-1, int c18=-1, int c19=-1,
int c20=-1, int c21=-1, int c22=-1, int c23=-1, int c24=-1, int c25=-1, int c26=-1, int c27=-1, int c28=-1, int c29=-1
>
struct s /* literal string - up to 30 symbols */
{
    typedef impl::strn<
        c0,
        typename s<
            c1,c2,c3,c4,c5,c6,c7,c8,c9,
            c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,
            c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,
            -1
        >::node
    > node;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt tend( it + node::length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        if( !node::do_match(it) )
            { it = t; return false;    }
        return true;
    }
};

template<> 
struct s<
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1>
{
    typedef impl::strnlast node;
};

template<
int c0,     int c1,     int c2 =-1, int c3 =-1, int c4 =-1, int c5 =-1, int c6 =-1, int c7 =-1, int c8 =-1, int c9 =-1,
int c10=-1, int c11=-1, int c12=-1, int c13=-1, int c14=-1, int c15=-1, int c16=-1, int c17=-1, int c18=-1, int c19=-1,
int c20=-1, int c21=-1, int c22=-1, int c23=-1, int c24=-1, int c25=-1, int c26=-1, int c27=-1, int c28=-1, int c29=-1
>
struct set /* charachter set - up to 30 chars - like "[ABCDEFabcdef]"*/
{
    typedef impl::setn<
        c0,
        typename set<
            c1,c2,c3,c4,c5,c6,c7,c8,c9,
            c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,
            c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,
            -1
        >::node
    > node;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && node::do_match(*it);
        if( res ) ++it;
        return res;
    }
};

template<> 
struct set<
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1>
{
    typedef impl::setnlast node;
};

template<wchar_t FRONT, wchar_t BACK, bool INCLUSIVE=true>
struct range /*charachter range - like "[a-d]" or "[^a-d]" */
{
    template<bool> struct sel {};
    //PXT_CASSERT((FRONT < BACK));

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, sel<true>)
    {
        bool res = (it != end) && (FRONT >= *it) && (*it <= BACK);
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, sel<false>)
    {
        return !do_match(it, end, sel<true>());
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return do_match(it, end, sel<INCLUSIVE>());
    }
};

struct ws /* whitespace chars */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && ((*it == ' ') || (*it == '\t'));
        if( res ) ++it;
        return res;
    }
};

struct digit /* numeric chars */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (*it >= '0') && (*it <= '9');
        if( res ) ++it;
        return res;
    }
};

struct alpha /* numeric chars */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (
            ((*it >= 'A') && (*it <= 'Z')) || 
            ((*it >= 'a') && (*it <= 'z'))
        );
        if( res ) ++it;
        return res;
    }
};

template<class RX>
struct star /*zero or more occurences of RX - like "(abc)*" */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        while( true )
        {
            InIt t(it);
            if( false == RX::match(it, end) || it == t )
                break;
        }
        return true;
    }
};

template<class RX>
struct plus /*one or more occurences of RX - like "(abc)+" */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end) && star<RX>::match(it, end);
    }
};

template<class RX>
struct opt /*optional occurence of RX - like "(abc)?" */
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        RX::match(it, end);
        return true;
    }
};

struct seqe {};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe, 
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe
>
struct seq 
{
    typedef impl::seqn<
        RX0,
        typename seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe>::node
    > node;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt t(it);
        bool res = node::do_match(it,end);
        if( !res ) it = t;
        return res;
    }
};

template<>
struct seq<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    typedef impl::seqnlast node;
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe, 
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe
>
struct alt /*alternative - like "(abc|def)" */
{
    typedef impl::altn<
        RX0,
        typename alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe>::node
    > node;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return node::do_match(it,end);
    }
};

template<>
struct alt<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    typedef impl::seqnlast node;
};
}//namespace rx_tmpl
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[4]: SRC: boost::(spirit|regex) для бедных
От: 0xDEADBEEF Ниоткуда  
Дата: 03.11.05 10:36
Оценка: 6 (1)
Здравствуйте, Дарней, Вы писали:

DEA>>Дело в том, что посредством автоматов некоторые вещи (маркирование подвыражений, обратные ссылки) сделать достаточно трудно, если не невозможно. По крайней мере, мне не удалось на автомате реализовать обратные ссылки.


Д>верно, некоторые вещи сделать нельзя. еще есть проблемы с метасимволами, насколько я понимаю

C метасимволами как раз проблемы нету. Конечно, если автомат NFA. Просто трактуешь этот метасимвол как "простой" символ — и при двустековом моделировании он отработает нормально. А вот для DFA — метасимволы — это пипец полный — в особенности если алфавит — юникодный — автомат разрастается до поистине ненормальных размеров.

Д>но можно попробовать прикрутить дополнительные фичи поверх автомата

...Тогда проще рекурсивно-нисходящим методом...

DEA>>Есть такие варианты:

DEA>>(1) останавливаемся, несмотря на то, что есть "не финальные" альтернативы. Получим наикратчайшее совпадение — автомат будет "уступчивым"
DEA>>(2) продложаем, пока финальное состояние не будет единственным в наборе альтернатив. Получим наидлиннейшее совпадение — автомат будет "жадным"

Д>а если внутри выражения есть несколько квантификаторов для разных его частей, из них один "жадный" а другой "ленивый"?

То же самое. Метишь состояния соответствующие окончанию подвыражения как "полуфинальные" и при моделировании "уступчивых" подвыражений предпочитаешь полуфинальное состояние всем остальным состояниям.
__________
16.There is no cause so right that one cannot find a fool following it.
Re[2]: Код: версия 0.00000001
От: ArtDenis Россия  
Дата: 14.11.03 04:26
Оценка: :)
Здравствуйте, TepMuHyc, Вы писали:

T> Проверено и работает:

T> — VC 6.0SP5 и старше
T> — Mingw GCC 3.3.1
T> ...

Офигеть! Как же всё это работает???

---------------------------------------------------------
СНП, Артёмов Денис. e-mail: artyomov <at> inbox.ru
Posted via RSDN NNTP Server 1.8 beta
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: Код: версия 0.00000003 - бенчмарки
От: WolfHound  
Дата: 26.11.03 05:28
Оценка: +1
Здравствуйте, TepMuHyc, Вы писали:

TMH>...запустил нижеприведенную програмку и просто офигел...

TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько
TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>


А не пойти ли тебе в boost с такими то результатами?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: SRC: boost::(spirit|regex) для бедных
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 14.11.03 08:56
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

[]

А сравнения будут?
... << RSDN@Home 1.1.0 stable >>
Re: SRC: boost::(spirit|regex) для бедных
От: Зверёк Харьковский  
Дата: 14.11.03 10:22
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>...Работы у меня сегодня не было, а настроение поизвращаться с C++ — было.

TMH>В результате всего этого, появился "шедевер" — шаблонная библиотека статических регулярных выражений, в чем-то смахивающая на SPIRIT. Вот только она гаараздо меньше — всего 7 килобайт. Ну, и гораздо примитивнее, конечно.

TMH>Основная ее фишка в том, что компиляция регулярного выражения проводится на этапе компиляции программы — прямо в исполнимый код (довольно страшноватенький — т.к. оптимизация еще впереди). А на этапе выполнения остается только пользоваться функцией поиска совпадений...


просто прелесть!
давно собирался сделать такую же штуку со спиритом (т.к. у тебя все же регекс)
удивительно, как до этого еще бустовцы не додумались.
а вот такой вопрос — насколько это эффективнее (и эфективнее ли?) классического бустового варианта?
я имею в виду все параметры: размер получившегося ехе-шника, скорость выполнения, простоту написания (ну тут явно налицо некоторый проигрыш, хотя, в принципе, можно привыкнуть)
FAQ — це мiй ай-кью!
Re[3]: SRC: boost::(spirit|regex) для бедных
От: Зверёк Харьковский  
Дата: 14.11.03 12:13
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>Моя билиотека — это голый и примитивный обход дерева (увы, сгенерировать конечный автомат на шаблонах мне еще слабО ).

а чо, давай сгенерируем что мешает-то?

TMH>Что же касается скорости, то моя билиотека будет слабже boost::regex как минимум в несколько раз. И только некоторые специально оптимизированные регулярные выражения могут позволить им сравниться в скорости.


а чем это обусловлено?

TMH>В целом, я бы рекомендовал применять мою библотеку когда:

TMH>1) Количество рег.выражений малО — не более нескольких 10-20.
TMH>2) Все они известны на compile-time
TMH>3) Скорость выполнения поиска совпадений не критична и/или рег.выражения достаточно простЫ.

в этих условиях она будет лучше, чем regex?
FAQ — це мiй ай-кью!
Re[3]: Код: версия 0.00000001
От: TepMuHyc  
Дата: 14.11.03 18:22
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А почему в качестве дефолтного символа в шаблонах использован -1 (русское "я"), а не 0 ?

...Вообще-то да... Спасибо.
В самом скором будущем заменю -1 на 0xBAADC0DE — надеюсь китайцы и прочие японцы против не будут
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: Re: Код: версия 0.00000002
От: WolfHound  
Дата: 15.11.03 06:33
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>- терминальные примитивы нечувствительные к регистру букв — думаю как сделать максимально гибко (эх, где ты, template typedef)

А так пойдет?
template<class T1, class T2>
struct some_else_template
{
    typedef some_template<T1, int, T2, float> type;
};
some_else_template<char, short>::type
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: SRC: boost::(spirit|regex) для бедных
От: GvozdodeR  
Дата: 15.11.03 16:41
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>...Работы у меня сегодня не было, а настроение поизвращаться с C++ — было.

TMH>В результате всего этого, появился "шедевер" — шаблонная библиотека статических регулярных выражений, в чем-то смахивающая на SPIRIT. Вот только она гаараздо меньше — всего 7 килобайт. Ну, и гораздо примитивнее, конечно.

TMH>Основная ее фишка в том, что компиляция регулярного выражения проводится на этапе компиляции программы — прямо в исполнимый код (довольно страшноватенький — т.к. оптимизация еще впереди). А на этапе выполнения остается только пользоваться функцией поиска совпадений...


Почти один в один boost::spirit. Только в boost::spirit почти не нужно извращаться с typedef'ами, выражение собирается с помощью вызовов функций. Собственно говоря, твоему подходу это не противоречит, т. к. в boost::spirit на низком уровне имеются подобные шаблоны. А интерфейс в духе boost::spirit можно добавить уже поверх всего написаного.
Re[4]: Код: версия 0.00000001
От: Кодт Россия  
Дата: 16.11.03 11:37
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

К>>А почему в качестве дефолтного символа в шаблонах использован -1 (русское "я"), а не 0 ?

TMH>...Вообще-то да... Спасибо.
TMH>В самом скором будущем заменю -1 на 0xBAADC0DE — надеюсь китайцы и прочие японцы против не будут

Где-нибудь наверху определи константу -- enum или просто #define. Чтобы потом можно было по-быстрому править...
Перекуём баги на фичи!
Re[5]: Код: версия 0.00000001
От: TepMuHyc  
Дата: 16.11.03 15:31
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Где-нибудь наверху определи константу -- enum или просто #define. Чтобы потом можно было по-быстрому править...

...это и ежу понятно — писать 0xBAADC0DE 28 раз — можно и мозоли на пальчиках заработать — проще
enum{ stopch = 0xBAADC0DE };
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: Код: версия 0.00000002
От: alexanderfedin США http://alexander-fedin.pixels.com/
Дата: 18.11.03 16:48
Оценка:
"TepMuHyc" <1583@news.rsdn.ru> wrote in message news:443651@news.rsdn.ru...
From: TepMuHyc http://vbourdo.cjb.net/


Изменения:
— подчищен код — убраны ненужные наследования, реализация всех рекурсивных шаблонов приведена к единообразию
— убраны все реверансы в строну forward_iterator — библиотека теперь поддерживает ТОЛЬКО random_access_iterator
— примитив alt<> теперь поддерживает до 10 подвыражений (раньше только 2)
— оптимизирован примитив s<> — убраны ненужные проверки конца последовательности.

Планы на следующие версии:
— примитив select<RX> — выделение подвыражений — будут изменения формата функции match()
— терминальные примитивы нечувствительные к регистру букв — думаю как сделать максимально гибко (эх, где ты, template typedef)
вот:

template <typename _Ty>
struct _typedef
{
    typedef _Ty value;
};

void main()
{
    _typedef<char>::value MyType;
}


Или... что ты имел в виду?
С уважением,
AlexanderFEDIN@iname.com
Posted via RSDN NNTP Server 1.8 beta
Respectfully,
Alexander Fedin.
Re: Код: версия 0.00000003
От: TepMuHyc  
Дата: 25.11.03 18:48
Оценка:
Изменения и прочая отдельным письмом...

#ifndef __STATIC_REGEX_H_INCLUDED__
#define    __STATIC_REGEX_H_INCLUDED__
namespace static_regex {

typedef wchar_t rx_char;
struct seqe {};
enum { stpc = 0xBAADC0DE };

template<rx_char E>
struct c {/* literal charachter */
    static bool char_match(rx_char ch)
        { return (E == ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (E == static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }
};

template<
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct s {/* literal string - up to 30 symbols */
    typedef s<
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    enum { length = 1 + tail::length };
    template<class InIt>
    static bool do_match(InIt& it)
    {
        return (c0 == static_cast<rx_char>(*it)) && tail::do_match(++it);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt tend( it + length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        bool res = do_match(it);
        if( !res ) it = t;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }
};
template<> struct s<
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    enum { length = 0 };

    template<class InIt>
    static bool do_match(InIt&)
        { return true; }
};

template<
    bool INCLUSIVE,
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc_ /* charachter class - like "[abcdEF]" or "[^abcdEF]" */
{
    typedef cc_<INCLUSIVE,
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    static bool char_match(rx_char ch)
        { return (c0 == ch) || tail::char_match(ch); }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && 
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }
};

template<> struct cc_<true,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{ 
    static bool char_match(rx_char ch)
        { return false; }
};

template<> struct cc_<false,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc:cc_<true,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct not_cc:cc_<false,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<rx_char F, rx_char B, bool INCLUSIVE=true>
struct range /* charachter range - like "[a-d]" or "[^a-d]" */
{
    static bool char_match(rx_char ch)
    {
        return (((F < B) ? F : B) <= ch) && (ch <= ((F < B) ? B : F));
    }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && 
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }
};

template<
    class CC0,      class CC1,      class CC2=seqe, class CC3=seqe, class CC4=seqe, 
    class CC5=seqe, class CC6=seqe, class CC7=seqe, class CC8=seqe, class CC9=seqe>
struct set {/* charachter set */
    typedef set<CC1,CC2,CC3,CC4,CC5,CC6,CC7,CC8,CC9,seqe> tail;

    static bool char_match(rx_char ch)
    {
        return CC0::char_match(ch) || tail::char_match(ch);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match( static_cast<rx_char>(*it) );
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }
};

template<> struct set<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{ 
    static bool char_match(rx_char)
        { return false; }
};

template<class RX>
struct star {/* zero or more occurences of RX - like "(abc)*" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        while( RX::match(it,end) );
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        while( RX::match(it,end,sel,nsel) );
        return true;
    }
};

template<class RX>
struct plus {/* one or more occurences of RX - like "(abc)+" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it,end) && star<RX>::match(it,end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        return RX::match(it,end,sel,nsel) && star<RX>::match(it,end,sel,nsel);
    }
};

template<class RX>
struct opt {/* optional occurence of RX - like "(abc)?" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        RX::match(it, end);
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        RX::match(it,end,sel,nsel);
        return true;
    }
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe, 
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct seq /* sequence of RX - like "(abc)(def)" */
{
    typedef seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end)
    {
        return RX0::match(it,end) && tail::do_match(it,end);
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        return RX0::match(it,end,sel,nsel) && tail::do_match(it,end,sel,nsel);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt itbk(it);
        if( !do_match(it,end) ) 
            { it = itbk; return false; }
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        InIt itbk(it);
        int nselbk = nsel;
        bool res = do_match(it,end,sel,nsel);
        if( !res ) {
            it = itbk;
            nsel = nselbk;
        }
        return res;
    }
};

template<> struct seq<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end)
        { return true; }
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
        { return true; }
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe, 
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct alt /* alternative - like "(abc|def)" */
{
    typedef alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res;
        InIt rxit(it); 
        res  = RX0::match(rxit,end);
        res |= tail::match(it,end);
        if( it < rxit ) 
            it = rxit;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        bool res;
        InIt rxit(it); 
        int rxnsel = nsel, tailnsel;
        res  = RX0::match(rxit,end,sel,rxnsel);
        res |= tail::match(it,end,sel,tailnsel = rxnsel);
        if( it <= rxit ) {
            it = rxit;
            nsel = rxnsel;
        } else
        if( res )
            for( ; rxnsel < tailnsel; rxnsel++, nsel++ )
            {
                sel[2*nsel  ] = sel[2*rxnsel  ];
                sel[2*nsel+1] = sel[2*rxnsel+1];
            }
        return res;
    }
};

template<> struct alt<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
        { return false; }
    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
        { return false; }
};

template<class RX>
struct select
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it,end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        InIt first(it);
        int nselbk = nsel++;
        bool res = RX::match(it,end,sel,nsel);
        if( res ) {
            sel[2*nselbk  ] = first;
            sel[2*nselbk+1] = it;
        } else {
            nsel = nselbk;
        }
        return res;
    }
};

//-////////////////////////////////////////////////////////////////////////
template<bool INCLUSIVE> struct ws_
    :cc<INCLUSIVE, ' ', '\t'>
    {};
typedef ws_<true> ws;
typedef ws_<false> not_ws;

template<bool INCLUSIVE> struct digit_
    :range<'0','9',INCLUSIVE>
    {};
typedef digit_<true> digit;
typedef digit_<false> not_digit;

template<bool INCLUSIVE> struct xdigit_
    :set< range<'0','9',INCLUSIVE>, range<'A','F',INCLUSIVE>, range<'a','f',INCLUSIVE> >
    {};
typedef digit_<true> xdigit;
typedef digit_<false> not_xdigit;

template<bool INCLUSIVE> struct alpha_
    :set< range<'A','Z',INCLUSIVE>, range<'a','z',INCLUSIVE> >
    {};
typedef alpha_<true> alpha;
typedef alpha_<false> not_alpha;

template<bool INCLUSIVE> struct alphanum_
    :set< alpha_<INCLUSIVE>, digit_<INCLUSIVE> >
    {};
typedef alphanum_<true> alphanum;
typedef alphanum_<false> not_alphanum;

struct endl:seq< opt< c<'\r'> >, c<'\n'> > {};
}//namespace static_regex
#endif//__STATIC_REGEX_H_INCLUDED__
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: Код: версия 0.00000003 - изменения
От: TepMuHyc  
Дата: 25.11.03 18:51
Оценка:
Изменения:
— как и было обещано, добавил примитив select<RX> для выделения подвыражений. Причем, без серьезной потери производительности, что особенно приятно. Теперь, немного о его использовании:
--выражение для выделения ответа FTP сервера (аналогичное приведенному в boost::regex) будет выглядеть так:
seq<
    select< plus<digit> >,               //код ответа
    select< alt<cc<'-',' '>, endl> >,    //символ переноса - если '-' - то ответ многострочный
    select< star<not_cc<'\r','\n'> > >,  //текст сообщения - все до конца строки
    opt<endl>                            //необязательный перевод строки
>

--вызов теста на совпадение будет выглядеть так:
int   nsubmatches;
char* submatches[2*3];//сколько всего планируется подвыражений - границы НЕ проверяются
char* text = "200 Hello world\n", ptr = text;
if( ftp_regex::match(ptr, ptr+strlen(ptr), submatches, nsubmatches=0) )
{//совпадает...
    submatches[0] //начало совпадения №1
    submatches[1] //конец совпадения №1
    
    submatches[2] //начало совпадения №2
    submatches[3] //конец совпадения №2
    
    submatches[4] //начало совпадения №3
    submatches[5] //конец совпадения №3
}


— основательно переработаны терминальные примитивы для работы с классами символов.
    c<'А'> - просто символ
    cс<'А','B','C'> - набор символов [ABC]
    not_cс<'А','B','C'> - набор символов [^ABC]
    range<'А','F',bool> - диапазон символов [A-F]
    set<CC0,CC1,...> - комбинанирование вышеуказанных примитивов -
        например класс символов [0-9A-Za-z_] будет выглядеть как 
        set<range<'0','9'>,range<'A','Z'>,range<'a','z'>,c<'_'> >


— добавлено еще несколько предопределенных примитивов
    ws - пробел или таб [ \t]
    not_ws - все кроме пробела или таба
    digit - десятичные цифры [0-9]
    not_digit - все кроме десятичных цифр
    xdigit - шестнадцатиричные цифры [0-9A-Fa-f]
    not_xdigit - все кроме шестнадцатиричных цифр
    alpha - английские буквы [A-Za-z]
    not_alpha - все кроме английских букв
    alphanum - английские буквы и цифры [0-9A-Za-z]
    not_alphanum - все кроме английских букв и цифр
    endl - конец строки (\r?\n)


— увы, не добавил case-insensitive примитивы — т.к. хорошо подумав, понял, что нечувствительность к регистру — штука очень уж зависящая от локали — а вариантов работы с локалями — масса и формализовать их не так уж легко. Тем более, совсем не хочется делать эту библиотечку зависящей от огромного и страшного пакета <locale>. Так что пусть данный вопрос остается желающим в качестве домашнего задания
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[3]: Код: версия 0.00000003 - бенчмарки
От: Зверёк Харьковский  
Дата: 25.11.03 19:20
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>...запустил нижеприведенную програмку и просто офигел...

TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько
TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>


хм... внушаить.
FAQ — це мiй ай-кью!
Re[3]: Код: версия 0.00000003 - бенчмарки
От: WFrag США  
Дата: 27.11.03 02:00
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>...запустил нижеприведенную програмку и просто офигел...

TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько
TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>



Попробуй со spirit-ом сравнить, интересно на результат посмотретью...
Re[3]: Код: версия 0.00000003 - бенчмарки
От: e-Xecutor Россия  
Дата: 08.12.03 09:14
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>


Эххх. Не догнал я тебя

# matches: 60000 # fails: 40000
my time: 29
# matches: 60000 # fails: 40000
boost time: 2462
# matches: 60000 # fails: 40000
skv time: 89


Что впрочем предсказуемо.
Но, учитывая, что мой код не inline, а статическая либа,
думаю что неплохо
Если компилировать не с /O2 а /O1, то одинаковое время
Но всё равно впечатляет, возьму на заметку
Re[4]: Код: версия 0.00000003 - бенчмарки
От: Аноним  
Дата: 09.12.03 23:49
Оценка:
Здравствуйте, e-Xecutor, Вы писали:
(отвечает TepMuHyc которого задолбал РСДН)

EX>
EX># matches: 60000 # fails: 40000
EX>my time: 29
EX># matches: 60000 # fails: 40000
EX>boost time: 2462
EX># matches: 60000 # fails: 40000
EX>skv time: 89
EX>


Что есть "skv" и с чем его можно покушать? Иными словами код в студию...
...А то я к аутпуту могу что хошь приписать... даже отрицательные числа...
Re[6]: Код: версия 0.00000001
От: Злость Россия  
Дата: 10.12.03 08:00
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>Здравствуйте, Кодт, Вы писали:


К>>Где-нибудь наверху определи константу -- enum или просто #define. Чтобы потом можно было по-быстрому править...

TMH>...это и ежу понятно — писать 0xBAADC0DE 28 раз — можно и мозоли на пальчиках заработать — проще
TMH>enum{ stopch = 0xBAADC0DE };

А я наверное заменю на 0xdeadbeef
Правда, Ложь — мне все одно — я имею свое мнение.
Если функция недокументированна — это не значит, что ее не используют все ваши конкуренты в своих продуктах.
Любой строй переходный и отрицать это значит быть закостенелым идиотом.
Re[5]: Код: версия 0.00000003 - бенчмарки
От: e-Xecutor Россия  
Дата: 10.12.03 08:21
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, e-Xecutor, Вы писали:

А>(отвечает TepMuHyc которого задолбал РСДН)

EX>>
EX>># matches: 60000 # fails: 40000
EX>>my time: 29
EX>># matches: 60000 # fails: 40000
EX>>boost time: 2462
EX>># matches: 60000 # fails: 40000
EX>>skv time: 89
EX>>


А>Что есть "skv" и с чем его можно покушать? Иными словами код в студию...

А>...А то я к аутпуту могу что хошь приписать... даже отрицательные числа...
skv — это моя библиотечка regexp-ов.
точнее это мои инициалы
Кода там больше ста кил, так что студия треснет, если его в неё внести
Всё не соберусь доку написать да выложить куда-нить...
Re[3]: Код: версия 0.00000003 - бенчмарки
От: Tonal- Россия www.promsoft.ru
Дата: 25.12.03 22:12
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

У меня не совирается на mingw32 v 3.2.3
пишет

bench.cpp: In function `bool is_ftpanswer(const std::string&)':
bench.cpp:37: no matching function for call to `
   static_regex::seq<static_regex::select<static_regex::plus<static_regex::digit>
   >, static_regex::select<static_regex::alt<static_regex::cc<45, 32, 
   -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, 
   -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, 
...



Да, это после того, как я в строках 14-16 явно квалифицировал select, а то g++ его с select-ом из winsock путал.
Re[4]: Код: версия 0.00000003 - бенчмарки
От: Tonal- Россия www.promsoft.ru
Дата: 27.12.03 16:58
Оценка:
T>У меня не собирается на mingw32 v 3.2.3
Решил проблему.

Всё дело было в функции is_ftpanswer
bool is_ftpanswer(const string& data)
{
    int nsubm;
    string::const_iterator subm[2*10];

    if( rx_ftp::match(data.begin(), data.end(), subm, nsubm=0) )
    {
        return true;
    }
    return false;
}


Объявление match выглядит так
template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)

и mingw естественно отказывался привязать временную переменную полученную из data.begin() к it.

Введение локальной переменной решило проблему.

Функция получилась такая:
bool is_ftpanswer(const string& data) {
  int nsubm = 0;
  string::const_iterator subm[2*10];
  string::const_iterator start = data.begin();
  return rx_ftp::match(start, data.end(), subm, nsubm);
}


Не совсем понятно как VC пропустил такую глюку.

Да, время окончания цикла наверное лучше мерить по окончанию цикла, а не в коде вывода отчёта.
... << RSDN@Home 1.1.0 stable >>
Re[3]: Код: версия 0.00000003 - бенчмарки
От: Tonal- Россия www.promsoft.ru
Дата: 27.12.03 18:13
Оценка:
TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько

Присоединяюсь!
Вот мои данные
Машина : P3 666Mz 256Mb WinXP
Компилер : g++ (GCC) 3.2.3 (mingw special 20030504-1)

Я немного переделал код — привожу ниже.

C:\Lang\Projects\test\static_regex>g++ -obench bench.cpp -lboost_regex
C:\Lang\Projects\test\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 1231
# matches: 60000 # fails: 40000
boost time: 13179

C:\Lang\Projects\test\static_regex>g++ -O2 -mcpu=pentiumpro -obench bench.cpp -lboost_regex
C:\Lang\Projects\test\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 120
# matches: 60000 # fails: 40000
boost time: 4757


Если использовать is_ftpanswer2 вместо is_ftpanswer
C:\static_regex>g++ -obench bench.cpp -lboost_regex
C:\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 1011
# matches: 60000 # fails: 40000
boost time: 13079

C:\static_regex>g++ -O2 -mcpu=pentiumpro -obench bench.cpp -lboost_regex
C:\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 80
# matches: 60000 # fails: 40000
boost time: 4617



#include <windows.h>
#include <string>
#include <iostream>
#include "static_regex.h"

#define BOOST_REGEX_STATIC_LINK
#include <boost/regex.hpp>

using std::string;
namespace
{
  using namespace static_regex;
  typedef
  seq<
    static_regex::select< plus<digit> >,               //код ответа
    static_regex::select< alt<cc<'-',' '>, endl> >,    //символ переноса - если '-' - то ответ многострочный
    static_regex::select< star<not_cc<'\r','\n'> > >,  //текст сообщения - все до конца строки
    opt<endl>                            //необязательный перевод строки
  >
  rx_ftp;

  boost::regex brx_ftp("([0-9]+)([\\- ]|(?:\r?\n))([^\r\n]*)(?:\r?\n)?");
}

string data[] = {
  "202Slightly malformed response\r\n",
  "200 Hello beutiful world\n",
  "201-Hello nice and beutiful world\n",
  "202-Hello sometimes nice and beutiful but mostly ugly world\r\n",
  "Not a response at all\r\n",
};

bool is_ftpanswer(const string& data) {
  int nsubm = 0;
  string::const_iterator subm[2*10];
  string::const_iterator start = data.begin();
  return rx_ftp::match(start, data.end(), subm, nsubm);
}

bool is_ftpanswer2(const string& data) {
  string::const_iterator start = data.begin();
  return rx_ftp::match(start, data.end());
}

bool bis_ftpanswer(const string& data) {
  boost::smatch what;
  return boost::regex_match(data, what, brx_ftp);
}

int main() {
  const int NITER = 20000;

  int nmatches = 0, nfails = 0;
  DWORD start = GetTickCount();
  for (int i=0; i < NITER; i++) {
    for (int r=0; r<5; r++)
      is_ftpanswer(data[r])
        ? ++nmatches : ++nfails;
  }
  DWORD stop = GetTickCount();
  std::cout << "# matches: " << nmatches << " # fails: " << nfails << std::endl;
  std::cout << "my time: " << (stop - start) << std::endl;

  nmatches = nfails = 0;
  start = GetTickCount();
  for (int i=0; i < NITER; i++) {
    for (int r=0; r<5; r++)
      bis_ftpanswer( data[r] )
        ? ++nmatches : ++nfails;
  }
  stop = GetTickCount();
  std::cout << "# matches: " << nmatches << " # fails: " << nfails << std::endl;
  std::cout << "boost time: " << (stop - start) << std::endl;
}
... << RSDN@Home 1.1.0 stable >>
Re[2]: Код: версия 0.00000003
От: Tonal- Россия www.promsoft.ru
Дата: 27.12.03 19:50
Оценка:
Напрашиваются ещё 2 полезные фичи:
"." — любой символ
"$" — конец последовательности

struct dot {/*any character*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      bool res = (it != end);
      if( res ) ++it;
      return res;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it,end);
  }
};

struct ends {/*end of input sequence*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return it == end;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it, end);
  }
};
... << RSDN@Home 1.1.0 stable >>
Re[2]: Код: версия 0.00000003
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 11:32
Оценка:
Обнаружил интересную фигню в работе с групировками:


Вот такое выражение:
Perl
/([abc])*/

static_regex
typedef star< select< cc<'a', 'b', 'c'> > > rx_star_sel_test;


Как вы думаете, сколько (максимум) груп оно найдёт в строке?
Ответ такой: всё зависит от строки.
в сторке "abc" 3 группы, в сторке "aaabbbccc" — 9.

Теперь немного изменим выражение:
Perl
/(?:([abc])|([def]))*/

static_regex
typedef star<
  alt< 
        select< cc<'a', 'b', 'c'> >,
        select< cc<'d', 'e', 'f'> >,
    >
> rx_star_sel_test;


И попытаемся ответить на вопрос как отделить группы найденные первой альтернативой от групп второй?
Ответ — никак.

Чтобы решить эту проблему, предлагаю придерживаться следуюших правил:
1) Количество найденных групп = количеству select-ов в выражении.
2) Несовпавшая группа обнуляется.
3) star и plus запоминают последнюю найденную группу.
4) для star — пустое совпадение — оба итератора указывают на место этого совпадения.

При этом можно на этапе компиляции подсчитать размер массива, нужного для хранения групп.
А так же несколько оптимизировать вычисления (если известно что групп нет — вызываем версию не работаюшую с группами).

Ниже приводиться исходник, где всё это реализованно.
//http://www.rsdn.ru/Forum/Message.aspx?mid=456007&only=1
//0.00000003
#ifndef __STATIC_REGEX_H_INCLUDED__
#define    __STATIC_REGEX_H_INCLUDED__
namespace static_regex {

typedef wchar_t rx_char;
struct seqe {};
enum { stpc = 0xBAADC0DE };
template<bool> struct grp_present {};

template<rx_char E>
struct c {/* literal charachter */
    static bool char_match(rx_char ch)
        { return (E == ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (E == static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct s {/* literal string - up to 30 symbols */
    typedef s<
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    enum { length = 1 + tail::length };
    template<class InIt>
    static bool do_match(InIt& it)
    {
        return (c0 == static_cast<rx_char>(*it)) && tail::do_match(++it);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt tend( it + length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        bool res = do_match(it);
        if( !res ) it = t;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};
template<> struct s<
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    enum { length = 0 };

    template<class InIt>
    static bool do_match(InIt&)
        { return true; }
};

template<
    bool INCLUSIVE,
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc_ /* charachter class - like "[abcdEF]" or "[^abcdEF]" */
{
    typedef cc_<INCLUSIVE,
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    static bool char_match(rx_char ch)
        { return (c0 == ch) || tail::char_match(ch); }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<> struct cc_<true,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<> struct cc_<false,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc:cc_<true,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct not_cc:cc_<false,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<rx_char F, rx_char B, bool INCLUSIVE=true>
struct range /* charachter range - like "[a-d]" or "[^a-d]" */
{
    static bool char_match(rx_char ch)
    {
        return (((F < B) ? F : B) <= ch) && (ch <= ((F < B) ? B : F));
    }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<
    class CC0,      class CC1,      class CC2=seqe, class CC3=seqe, class CC4=seqe,
    class CC5=seqe, class CC6=seqe, class CC7=seqe, class CC8=seqe, class CC9=seqe>
struct set {/* charachter set */
    typedef set<CC1,CC2,CC3,CC4,CC5,CC6,CC7,CC8,CC9,seqe> tail;

    static bool char_match(rx_char ch)
    {
        return CC0::char_match(ch) || tail::char_match(ch);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match( static_cast<rx_char>(*it) );
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<> struct set<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    static bool char_match(rx_char)
        { return false; }
};

template<class RX>
struct star {/* zero or more occurences of RX - like "(abc)*" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        while( RX::match(it,end) );
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
      return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      InIt _sel2[2*RX::sel_len];
      int _nsel = 0, _nsel2 = 0;
      while (RX::match(it, end, _sel2, _nsel)) {
        for (int i = 0; i < 2*_nsel; ++i)
          sel[i] = _sel2[i];
        _nsel2 = _nsel;
        _nsel = 0;
      }
      if (_nsel2)
        nsel += _nsel2;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it,end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
};

template<class RX>
struct plus {/* one or more occurences of RX - like "(abc)+" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end) && star<RX>::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
        return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      int _nsel2 = 0;
      InIt _sel2[2*RX::sel_len];
      if (!RX::match(it, end, _sel2, _nsel2))
        return false;

      int _nsel = 0;
      star<RX>::match(it, end, sel, _nsel);
      if (!_nsel) {
        for (int i = 0; i < _nsel2; ++i)
          sel[i] = _sel2[i];
        _nsel = _nsel2;
      }
      nsel += _nsel;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it, end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
};

template<class RX>
struct opt {/* optional occurence of RX - like "(abc)?" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        RX::match(it, end);
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        RX::match(it, end, sel, nsel);
        return true;
    }

    enum {sel_len = RX::sel_len};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct seq /* sequence of RX - like "(abc)(def)" */
{
    typedef seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end)
    {
        return RX0::match(it,end) && tail::do_match(it,end);
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        return RX0::match(it, end, sel, nsel)
            && tail::do_match(it, end, sel + RX0::sel_len, nsel);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt itbk(it);
        bool res = do_match(it, end);
        if (!res)
          it = itbk;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        InIt itbk(it);
        int nselbk = nsel;
        bool res = do_match(it, end, sel, nsel);
        if( !res ) {
            it = itbk;
            nsel = nselbk;
        }
        return res;
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
};

template<> struct seq<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end)
        { return true; }
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
        { return true; }

    enum {sel_len = 0};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct alt /* alternative - like "(abc|def)" */
{
    typedef alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        if (RX0::match(it, end))
          return true;
        else
          return tail::match(it, end);
    }

    template<class InIt>
      static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
        if (RX0::match(it, end, sel, nsel))
          return true;
        else
          return tail::match(it, end, sel + RX0::sel_len, nsel);
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
};

template<> struct alt<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
        { return false; }
    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
        { return false; }

    enum {sel_len = 0};
};

template<class RX>
struct select
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      InIt first(it);
      int _nsel = 0;
      if (RX::match(it, end, sel + 2, _nsel)) {
        sel[0] = first;
        sel[1] = it;
        nsel += 1 + _nsel;
        return true;
      } else {
        sel[0] = sel[1] = InIt();
        return false;
      }
    }

    enum {sel_len = 1};
};

//-////////////////////////////////////////////////////////////////////////
template<bool INCLUSIVE> struct ws_
    :cc<INCLUSIVE, ' ', '\t'>
    {};
typedef ws_<true> ws;
typedef ws_<false> not_ws;

template<bool INCLUSIVE> struct digit_
    :range<'0','9',INCLUSIVE>
    {};
typedef digit_<true> digit;
typedef digit_<false> not_digit;

template<bool INCLUSIVE> struct xdigit_
    :set< range<'0','9',INCLUSIVE>, range<'A','F',INCLUSIVE>, range<'a','f',INCLUSIVE> >
    {};
typedef digit_<true> xdigit;
typedef digit_<false> not_xdigit;

template<bool INCLUSIVE> struct alpha_
    :set< range<'A','Z',INCLUSIVE>, range<'a','z',INCLUSIVE> >
    {};
typedef alpha_<true> alpha;
typedef alpha_<false> not_alpha;

template<bool INCLUSIVE> struct alphanum_
    :set< alpha_<INCLUSIVE>, digit_<INCLUSIVE> >
    {};
typedef alphanum_<true> alphanum;
typedef alphanum_<false> not_alphanum;

struct endl:seq< opt< c<'\r'> >, c<'\n'> > {};

//Shura added
struct dot {/*any character*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      bool res = (it != end);
      if( res ) ++it;
      return res;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it,end);
  }

  enum {sel_len = 0};
};//dot /*any character*/

struct ends {/*end of input sequence*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return it == end;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it, end);
  }

  enum {sel_len = 0};
};//ends /*end of input sequence*/

}//namespace static_regex
#endif//__STATIC_REGEX_H_INCLUDED__
... << RSDN@Home 1.1.0 stable >>
Предложения по дальнейшей разработке
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 12:11
Оценка:
Предложения по дальнейшей разработке:

1) Может всёж-таки завести структурку для группировки — ато некошерно как-то получается...
К тому же требующийся размер массива можно теперь вычислить.

2) Выражение типа
Perl
/.*\.cpp/

static_regex
typedef seq< star<dot>, c<'.'>, s<'c', 'p', 'p'> > rx_cpp_file;

Не могут быть найдены — т.к. операторы повторения (star, plus, opt) реализованы как "неуступчивые". Т.е. заняв какой-либо символ, они не умеют отдать его назад.
К сожалению проблема не в коде этих операторов, а во взаимодействии их и последующих.
Т.е. эту проблему, предположительно, можно решить подправив код seq::match.

3) Завести перегруженные функции помощники, типа:
//Приверка последовательности
template <class RX, class Iter>
bool test(RX, Iter first, Iter last);

//Приверка последовательности и заполнение групп
template <class RX, class Iter>
bool match(RX, Iter first, Iter last, RX::groups&);

//Поиск в последовательности
template <class RX, class Iter>
bool search(RX, Iter first, Iter last, RX::groups&);

Можно ещё для string перегрузить...
... << RSDN@Home 1.1.0 stable >>
Re: Предложения по дальнейшей разработке
От: Аноним  
Дата: 29.12.03 13:12
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Предложения по дальнейшей разработке:


T>1) Может всёж-таки завести структурку для группировки — ато некошерно как-то получается...

Пришел к аналогичному выводу. Скоро выложу.

T>2) Выражение типа "/.*\.cpp/" Не могут быть найдены.

Известная беда всех реализаций регулярных выражений.
Что же касается "нежадных" операторов, то у регулярного выражения есть задача: "найти наидлиннейшее совпадение". Чтобы решить ее с "нежадными" операторами, придется перепробовать все комбинаци их "жадности" — от "совсем нежадный" до "почти жадный". Задачка не для слабонервных. И сложность у нее полиномиальная, а то и (не приведи господь) экспоненциальная.

Так что увольте, "нежадные" операторы не будут реализованы никогда — проще потребовать от программиста
чтобы он писал выражения учитывающие "жадность".

например так:
/.*\.cpp/ <==> /[^.]*\.cpp/


T>3) Завести перегруженные функции помощники, типа:

Никто не мешает. Но это лучше отдать на откуп "прикладному программисту"

T>//Поиск в последовательности

T>template <class RX, class Iter>
T>bool search(RX, Iter first, Iter last, RX::groups&);
T>[/ccode]
Это еще одна задача из разряда "и хочется и колется"..
"brute force" подход всегда открыт, но мне не нравится его сложность: O(length(rx) * length(string))
Думаю как притянуть сюда алгоритм Кнута-Морриса-Пратта, но в данной реализации это скорее всего нереализуемо (точнее, реализуемо, но компилируется ОЧЕНЬ долго)


T>Можно ещё для string перегрузить...

Опять-таки "прикладной программист" напишет этот костыль для себя гораздо лучше чем я для него.
Re[2]: Предложения по дальнейшей разработке
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 19:13
Оценка:
Ура, я тут не один! ;-в

T>>2) Выражение типа "/.*\.cpp/" Не могут быть найдены.

А>Известная беда всех реализаций регулярных выражений.
А>Что же касается "нежадных" операторов, то у регулярного выражения есть задача: "найти наидлиннейшее совпадение". Чтобы решить ее с "нежадными" операторами, придется перепробовать все комбинаци их "жадности" — от "совсем нежадный" до "почти жадный". Задачка не для слабонервных. И сложность у нее полиномиальная, а то и (не приведи господь) экспоненциальная.
Мне кажется, ты немножко путаешь понятия:
Квалификатор повторения может быть "жадным" и "не жадным".
"Жадные" могут быть "уступчивым" и "неуступчивым".
Так что имеем 3 варианта.
Сейчас у нас "жадный неуступчивый", т.е. система не поддерживает откатов.
Это не даёт написать выражение типа "оканчивается на" в обшем виде. Например нельзя написать выражение для выделения доменов первого уровня в url-е, или для выделения имени файла (ведь "." — допустимый символ). Для обработки подобных выражений придётся прибегать к другой библиотеке, а не хочется.
А насчёт "наидлиннейшего" совпадения — для отыскания оного, надо перебрать все возможные варианты.
Пример
"abcc"
/(a*)(abc+|b)/

Тут "наидлиннейшее" бидет вся сторка по пустой первой группе и первой алтернативе во второй. Её и найдёт ДКА, или POSIX НКА. Ну а обычный НКА или интерпретатор найдёт только "ab".

Так что я предлагаю не очень напрягаться по этому поводу (Perl ведь не напрягаются). Лучше попытаться построить ДКА.

А на счёт нетривиальности задачки — всё это достаточно просто реализовать (код ниже).
Чтобы не слишком тормазило решения такие:
А) Для всех классов определить константу undoable — откатываемость.
А1) Для терминалов (c, cc, s...) — false.
А2) Для повторителей и альтернативы — true.
А3) Для контейнеров — вычисляется по или от содержимого.
Б) В последовательности разбираем разные варианты и пишем код.
В) Создаём класс контейнер noundo — который делает содержащееся в нём выражение неуступчивым (undoable = false).

Для моего бенчмарка эта версия даёт всего лишь 4-5 кратный выигрышь в скорости по сравнению с boost::regex.
Но, если переписать варажение с использованием noundo в разумнвх местах, то опять выигрыш примерно на 1,5-2 порядка!

Выражение вот:
  typedef seq<
    noundo< select< plus<digit> > >,               //код ответа
    noundo< select< alt<cc<'-',' '>, endl> > >,    //символ переноса - если '-' - то ответ многострочный
    select< star<not_cc<'\r','\n'> > >,            //текст сообщения - все до конца строки
    opt<endl>                            //необязательный перевод строки
  >
  rx_ftp2;

Вот результат:
C:\static_regex>g++ -O2 -mcpu=pentiumpro -pipe -obench bench.cpp -lboost_regex
C:\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 1802
# matches: 60000 # fails: 40000
my noundo time: 140
# matches: 60000 # fails: 40000
boost time: 4647


T>>3) Завести перегруженные функции помощники, типа:

А>Никто не мешает. Но это лучше отдать на откуп "прикладному программисту"
Я всёж таки изобразил 2 перегруженных варианта test. Зачем плодить везде одинаковые куски, если можно их вставить в библиотеку не нарушая единства.
Остальные — подожду структурку для групп. ;-в

T>>//Поиск в последовательности
T>>template <class RX, class Iter>
T>>bool search(RX, Iter first, Iter last, RX::groups&);
T>>

А>Это еще одна задача из разряда "и хочется и колется"..
А>"brute force" подход всегда открыт, но мне не нравится его сложность: O(length(rx) * length(string))
А>Думаю как притянуть сюда алгоритм Кнута-Морриса-Пратта, но в данной реализации это скорее всего нереализуемо (точнее, реализуемо, но компилируется ОЧЕНЬ долго)
Тут тоже есть много вариантов для оптимизации... хотя согласен, надо пока обдумать...

Таки код:
//http://www.rsdn.ru/Forum/Message.aspx?mid=456007&only=1
//0.00000003
#ifndef __STATIC_REGEX_H_INCLUDED__
#define    __STATIC_REGEX_H_INCLUDED__
namespace static_regex {

typedef wchar_t rx_char;
struct seqe {};
enum { stpc = 0xBAADC0DE };
template<bool> struct grp_present {};

template<rx_char E>
struct c {/* literal charachter */
    static bool char_match(rx_char ch)
        { return (E == ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (E == static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct s {/* literal string - up to 30 symbols */
    typedef s<
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    enum { length = 1 + tail::length };
    template<class InIt>
    static bool do_match(InIt& it)
    {
        return (c0 == static_cast<rx_char>(*it)) && tail::do_match(++it);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt tend( it + length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        bool res = do_match(it);
        if( !res ) it = t;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};
template<> struct s<
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    enum { length = 0 };

    template<class InIt>
    static bool do_match(InIt&)
        { return true; }
};

template<
    bool INCLUSIVE,
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc_ /* charachter class - like "[abcdEF]" or "[^abcdEF]" */
{
    typedef cc_<INCLUSIVE,
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    static bool char_match(rx_char ch)
        { return (c0 == ch) || tail::char_match(ch); }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<> struct cc_<true,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<> struct cc_<false,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc:cc_<true,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct not_cc:cc_<false,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<rx_char F, rx_char B, bool INCLUSIVE=true>
struct range /* charachter range - like "[a-d]" or "[^a-d]" */
{
    static bool char_match(rx_char ch)
    {
        return (((F < B) ? F : B) <= ch) && (ch <= ((F < B) ? B : F));
    }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<
    class CC0,      class CC1,      class CC2=seqe, class CC3=seqe, class CC4=seqe,
    class CC5=seqe, class CC6=seqe, class CC7=seqe, class CC8=seqe, class CC9=seqe>
struct set {/* charachter set */
    typedef set<CC1,CC2,CC3,CC4,CC5,CC6,CC7,CC8,CC9,seqe> tail;

    static bool char_match(rx_char ch)
    {
        return CC0::char_match(ch) || tail::char_match(ch);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match( static_cast<rx_char>(*it) );
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<> struct set<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    static bool char_match(rx_char)
        { return false; }
};

template<class RX>
struct star {/* zero or more occurences of RX - like "(abc)*" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        while( RX::match(it,end) );
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
      return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      InIt _sel2[2*RX::sel_len];
      int _nsel = 0, _nsel2 = 0;
      while (RX::match(it, end, _sel2, _nsel)) {
        for (int i = 0; i < 2*_nsel; ++i)
          sel[i] = _sel2[i];
        _nsel2 = _nsel;
        _nsel = 0;
      }
      if (_nsel2)
        nsel += _nsel2;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it, end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
    enum {undoable = 1};
};

template<class RX>
struct plus {/* one or more occurences of RX - like "(abc)+" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end) && star<RX>::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
        return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      int _nsel2 = 0;
      InIt _sel2[2*RX::sel_len];
      if (!RX::match(it, end, _sel2, _nsel2))
        return false;

      int _nsel = 0;
      star<RX>::match(it, end, sel, _nsel);
      if (!_nsel) {
        for (int i = 0; i < _nsel2; ++i)
          sel[i] = _sel2[i];
        _nsel = _nsel2;
      }
      nsel += _nsel;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it, end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
    enum {undoable = 1};
};

template<class RX>
struct opt {/* optional occurence of RX - like "(abc)?" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        RX::match(it, end);
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        RX::match(it, end, sel, nsel);
        return true;
    }

    enum {sel_len = RX::sel_len};
    enum {undoable = 1};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct seq /* sequence of RX - like "(abc)(def)" */
{
    typedef seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template <bool> struct simple{};

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, simple<true>) {
        return RX0::match(it, end) && tail::do_match(it, end);
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, simple<false>) {
      for (InIt _end = end; it != _end; --_end) {
        InIt _it = it;
        if (!RX0::match(_it, _end))
          return false;
        if (tail::do_match(_it, end)) {
          it = _it;
          return true;
        }
      }
      return false;
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end) {
      return do_match(
        it, end, simple<(!RX0::undoable || tail::end_seq)>()
      );
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, simple<true>
    ) {
      return RX0::match(it, end, sel, nsel)
          && tail::do_match(it, end, sel + 2*RX0::sel_len, nsel);
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<false>
    ) {
      for (InIt _end = end; it != _end; --_end) {
        InIt _it(it);
        if (!RX0::match(_it, _end))
          return false;
        if (tail::do_match(_it, end, sel, nsel)) {
          it = _it;
          return true;
        }
      }
      return false;
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      for (InIt _end = end; it != _end; --_end) {
        InIt _it(it);
        InIt _sel[RX0::sel_len + 1];
        int _nsel = 0;
        if (!RX0::match(_it, _end, _sel, _nsel))
          return false;
        if (tail::do_match(_it, end, sel + 2*RX0::sel_len, nsel)) {
          for (int i = 0; i < 2*_nsel; ++i)
            sel[i] = _sel[i];
          nsel += _nsel;
          it = _it;
          return true;
        }
      }
      return false;
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, simple<false>
    ) {
      return do_match(it, end, sel, nsel, grp_present<(!!RX0::sel_len)>());
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return do_match(
        it, end, sel, nsel, simple<(!RX0::undoable || tail::end_seq)>()
      );
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end) {
      InIt itbk(it);
      bool res = do_match(it, end);
      if (!res)
        it = itbk;
      return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
        InIt itbk(it);
        int nselbk = nsel;
        bool res = do_match(it, end, sel, nsel);
        if( !res ) {
            it = itbk;
            nsel = nselbk;
        }
        return res;
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
    enum {undoable = RX0::undoable || tail::undoable};
    enum {end_seq = 0};
};

template<> struct seq<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool do_match(InIt&, const InIt&)
        { return true; }
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
        { return true; }

    enum {sel_len = 0};
    enum {undoable = 0};
    enum {end_seq = 1};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct alt /* alternative - like "(abc|def)" */
{
    typedef alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        if (RX0::match(it, end))
          return true;
        else
          return tail::match(it, end);
    }

    template<class InIt>
      static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
        if (RX0::match(it, end, sel, nsel))
          return true;
        else
          return tail::match(it, end, sel + 2*RX0::sel_len, nsel);
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
    enum {undoable = 1};
};

template<> struct alt<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
        { return false; }
    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
        { return false; }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<class RX>
struct select
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      InIt first(it);
      int _nsel = 0;
      if (RX::match(it, end, sel + 2, _nsel)) {
        sel[0] = first;
        sel[1] = it;
        nsel += 1 + _nsel;
        return true;
      } else {
        sel[0] = sel[1] = InIt();
        return false;
      }
    }

    enum {sel_len = 1};
    enum {undoable = RX::undoable};
};

//-////////////////////////////////////////////////////////////////////////
template<bool INCLUSIVE> struct ws_
    :cc<INCLUSIVE, ' ', '\t'>
    {};
typedef ws_<true> ws;
typedef ws_<false> not_ws;

template<bool INCLUSIVE> struct digit_
    :range<'0','9',INCLUSIVE>
    {};
typedef digit_<true> digit;
typedef digit_<false> not_digit;

template<bool INCLUSIVE> struct xdigit_
    :set< range<'0','9',INCLUSIVE>, range<'A','F',INCLUSIVE>, range<'a','f',INCLUSIVE> >
    {};
typedef digit_<true> xdigit;
typedef digit_<false> not_xdigit;

template<bool INCLUSIVE> struct alpha_
    :set< range<'A','Z',INCLUSIVE>, range<'a','z',INCLUSIVE> >
    {};
typedef alpha_<true> alpha;
typedef alpha_<false> not_alpha;

template<bool INCLUSIVE> struct alphanum_
    :set< alpha_<INCLUSIVE>, digit_<INCLUSIVE> >
    {};
typedef alphanum_<true> alphanum;
typedef alphanum_<false> not_alphanum;

struct endl:seq< opt< c<'\r'> >, c<'\n'> > {};

//Shura added
struct dot {/*any character*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      bool res = (it != end);
      if( res ) ++it;
      return res;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it,end);
  }

  enum {sel_len = 0};
  enum {undoable = 0};
};//dot /*any character*/

struct ends {/*end of input sequence*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return it == end;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it, end);
  }

  enum {sel_len = 0};
  enum {undoable = 0};
};//ends /*end of input sequence*/

template <class RX>
struct noundo {/*modifer for non undoable repeats*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return RX::match(it, end);
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
  {
      return RX::match(it, end, sel, nsel);
  }
  enum {sel_len = RX::sel_len};
  enum {undoable = 0};
};//noundo

//Приверка последовательности
template <class RX, class Iter>
bool test(RX, Iter first, Iter last) {
  return RX::match(first, last) && first == last;
}

template <class RX, class String>
bool test(RX, const String& str) {
  typename str::const_iterator first = str.begin();
  return RX::match(first, str.end()) && first == str.end();
}

}//namespace static_regex
#endif//__STATIC_REGEX_H_INCLUDED__
... << RSDN@Home 1.1.0 stable >>
Re[3]: Предложения по дальнейшей разработке
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 20:11
Оценка:
Вкралась зловредная ошибка.
Вот правильный вариант:
template <class RX, class String>
bool test(RX, const String& str) {
  typename String::const_iterator first = str.begin();
  return RX::match(first, str.end()) && first == str.end();
}
... << RSDN@Home 1.1.0 stable >>
Re: Код: версия 0.00000004
От: Аноним  
Дата: 06.01.04 18:04
Оценка:
Дофигища изменений: контейнеры для совпадений, обратные ссылки, "нежадные" и "жадные" операторы-повторители. Подробнее — отдельным письмом.

#ifndef __STATIC_REGEX_H_INCLUDED__
#define    __STATIC_REGEX_H_INCLUDED__

namespace static_regex {

typedef wchar_t rx_char;
typedef unsigned int rx_int;
struct _Sqe {};
enum { _Stc = 0xBAADC0DE };

//-////////////////////////////////////////////////////////////////////////

/**\ingroup grpSRXM
Single match.
\sa mark - capture a %submatch*/
template<class IT>
class submatch {
    rx_int id_; IT begin_; IT end_;
public:
    submatch() {}
    submatch(rx_int id, const IT& begin, const IT& end)
        :id_(id),begin_(begin),end_(end) {}
    template<class IT1> submatch(const submatch<IT1>& rhs)
        :id_(rhs.id()),begin_(rhs.begin()),end_(rhs.end()) {}
    ///get match identifier
    rx_int id() const { return id_; }
    ///get match beginning
    const IT& begin() const { return begin_; }
    ///get match ending
    const IT& end() const { return end_; }
    ///match length
    std::size_t length() const { return end_ - begin_; }
};

template<class IT, std::size_t N> class match_array;

template<class IT, std::size_t N>
void set_match_count(match_array<IT,N>& m, std::size_t cnt)
    { if(cnt > N) cnt = N; m.nmatch_ = cnt; }

template<class IT, std::size_t N>
submatch<IT>& get_match_at(match_array<IT,N>& m, std::size_t pos)
    { return m.match_[pos]; }

/**\ingroup grpSRXM
Submatch container based on static array.
\param IT iterator type
\param N  container capcity*/
template<class IT, std::size_t N=31>
class match_array {
    match_array(const match_array&);
    match_array& operator=(const match_array&);
public:
    typedef submatch<IT> match_type;
    typedef const match_type* iterator;
public:
    match_array()
        :nmatch_(0) {}
    explicit match_array(std::size_t)
        :nmatch_(0) {}
public:
    std::size_t size() const
        { return nmatch_; }
    match_array& reset()
        { nmatch_ = 0; return *this; }
    const match_type& operator[](std::size_t pos) const
        { return match_[pos]; }
    iterator begin() const { return match_; }
    iterator end() const { return match_ + nmatch_; }
private:
    match_type match_[N+1];
    std::size_t nmatch_;

#if defined(_MSC_VER) && _MSC_VER < 1300 //MSVC 6.0
    friend void set_match_count(match_array& m, std::size_t cnt);
    friend submatch<IT>& get_match_at(match_array& m, std::size_t pos);
#else
    friend void set_match_count<>(match_array& m, std::size_t cnt);
    friend submatch<IT>& get_match_at<>(match_array& m, std::size_t pos);
#endif//MSVC 6.0
};

template<class IT, class A> class match_vector;

template<class IT, class A>
void set_match_count(match_vector<IT,A>& m, std::size_t cnt)
    { m.resize(cnt); }

template<class IT, class A>
submatch<IT>& get_match_at(match_vector<IT,A>& m, std::size_t pos)
    { return m.at(pos); }

/**\ingroup grpSRXM
Submatch container based on std::vector.
\param IT iterator type
\param A  allocator type*/
template<class IT, class A=std::allocator< submatch<IT> > >
class match_vector
    :std::vector<submatch<IT>,A>
{
    match_vector(const match_vector&);
    match_vector& operator=(const match_vector&);
    typedef std::vector<submatch<IT>,A> base;
public:
    typedef submatch<IT> match_type;
    typedef typename base::const_iterator iterator;
public:
    match_vector()
        {}
    explicit match_vector(std::size_t size)
        { base::reserve(size); }
public:
    using base::size;

    match_vector& reset()
        { base::resize(0); return *this; }
    const match_type& operator[](std::size_t pos) const
        { return base::at(pos); }
    iterator begin() const { return base::begin(); }
    iterator end() const { return base::end(); }

#if defined(_MSC_VER) && _MSC_VER < 1300 //MSVC 6.0
    friend void set_match_count(match_vector& m, std::size_t cnt);
    friend submatch<IT>& get_match_at(match_vector& m, std::size_t pos);
#else
    friend void set_match_count<>(match_vector& m, std::size_t cnt);
    friend submatch<IT>& get_match_at<>(match_vector& m, std::size_t pos);
#endif//MSVC 6.0
};

//-////////////////////////////////////////////////////////////////////////
#define _SRX_NULLABLE(b) \
    enum{ is_nullable = (b) }

struct _Norx {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return false; }
};

/**\ingroup grpSRXL
Literal string - up to 30 symbols */
template<
    rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
    rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
    rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct s {
    typedef s<c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,
c23,c24,c25,c26,c27,c28,c29,_Stc> tail;

    _SRX_NULLABLE(false);

    enum { length = 1 + tail::length };

    template<class InIt>
    static bool do_match(InIt& it)
        { return (c0 == static_cast<rx_char>(*it)) && tail::do_match(++it); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt tend( it + length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        bool res = do_match(it);
        if( !res ) it = t;
        return res;
    }
};
template<> struct s<
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc>
{
    enum { length = 0 };

    template<class InIt>
    static bool do_match(InIt&)
        { return true; }
};

/**\ingroup grpSRXL
Single literal charachter */
template<rx_char E>
struct c {
    _SRX_NULLABLE(false);

    static bool char_match(rx_char ch)
        { return (E == ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        bool res = (it != end) && (E == static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }
};

/**\ingroup grpSRXL
Charachter class - like \c "[abcdEF]" or \c "[^abcdEF]"*/
template<
    bool INCLUSIVE,
    rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
    rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
    rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct cc_ {
    typedef cc_<INCLUSIVE,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,
c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,_Stc> tail;

    _SRX_NULLABLE(false);

    static bool char_match_(rx_char ch)
        { return (c0 == ch) || tail::char_match_(ch); }
    static bool char_match(rx_char ch)
        { return INCLUSIVE ? char_match_(ch) : !char_match_(ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES&)
    {
        bool res = (it != end) && 
            char_match(static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }
};
template<> struct cc_<true,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc>
{ 
    static bool char_match_(rx_char ch)
        { return false; }
};
template<> struct cc_<false,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc>
{
    static bool char_match_(rx_char ch)
        { return false; }
};

/**\ingroup grpSRXL
Charachter class - like \c "[abcdEF]"*/
template<
rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct cc:cc_<true,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
c21,c22,c23,c24,c25,c26,c27,c28,c29> {};

/**\ingroup grpSRXL
Charachter class - like \c "[^abcdEF]"*/
template<
rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct not_cc:cc_<false,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,
c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29> {};

/**\ingroup grpSRXL
Charachter range - like \c "[a-d]" or \c "[^a-d]" */
template<rx_char F, rx_char B, bool INCLUSIVE=true>
struct cr {
    _SRX_NULLABLE(false);

    static bool char_match_(rx_char ch)
        { return (((F < B) ? F : B) <= ch) && (ch <= ((F < B) ? B : F)); }
    static bool char_match(rx_char ch)
        { return INCLUSIVE ? char_match_(ch) : !char_match_(ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES&)
    {
        bool res = (it != end) && 
            char_match(static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }
};

/**\ingroup grpSRXL
Charachter set - a combination of two or more charachter set classes.
\param CC0-CC9 charachter set classes
\sa charachter set classes: c, cc, cr, cs */
template<
    class CC0,      class CC1,      class CC2=_Sqe, class CC3=_Sqe, class CC4=_Sqe, 
    class CC5=_Sqe, class CC6=_Sqe, class CC7=_Sqe, class CC8=_Sqe, class CC9=_Sqe>
struct cs {
    typedef cs<CC1,CC2,CC3,CC4,CC5,CC6,CC7,CC8,CC9,_Sqe> tail;

    _SRX_NULLABLE(false);

    static bool char_match(rx_char ch)
        { return CC0::char_match(ch) || tail::char_match(ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        bool res = (it != end) &&
            char_match( static_cast<rx_char>(*it) );
        if( res ) ++it;
        return res;
    }
};
template<> struct cs<_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe> { 
    static bool char_match(rx_char)
        { return false; }
};

/**\ingroup grpSRXO
Zero or more occurences of \c RX - like \c "(abc)*"
\param RX regular expression class*/
template<class RX>
struct star {
    _SRX_NULLABLE(true);
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { while( RX::match(it,end,m) ); return true; }
};

/**\ingroup grpSRXO
One or more occurences of \c RX - like \c "(abc)+"
\param RX regular expression class*/
template<class RX>
struct plus {
    _SRX_NULLABLE(false);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::match(it,end,m) && star<RX>::match(it,end,m); }
};

/**\ingroup grpSRXO
Optional occurence of RX - like \c "(abc)?"
\param RX regular expression class*/
template<class RX>
struct opt {
    _SRX_NULLABLE(true);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { RX::match(it,end,m); return true; }
};

/**\ingroup grpSRXO
Repetition - like \c "(abc){3,5}"
\param RX regular expression class
\param N1 number of times \c RX \em must be matched 
\param N2 number of times \c RX \em may match - must be greater or equal to \c N1*/
template<std::size_t N1, std::size_t N2, class RX>
struct rep {
    _SRX_NULLABLE(( N1==0 ));
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        std::size_t n, nmbk = m.size();
        InIt itbk(it);

        n = N1;
        while( n && RX::match(it,end,m) ) --n;
        if( n ) { it = itbk; set_match_count(m,nmbk); return false; }

        n = N2 - N1;
        while( n && RX::match(it,end,m) ) --n;
        return true;
    }
};

template<class RX> struct _Sqtw:RX {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::do_match(it,end,m); }
};

template<class M,class N,class U>
struct _Sqmw:M {
    typedef N rx_next;
    typedef U rx_unext;
};

/**\ingroup grpSRXO
Sequence of expressions - like \c "(abc)(def)"
\param RX0-RX9 regular expression class*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct seq {
    typedef _Sqtw< seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,_Sqe> > tail;

    _SRX_NULLABLE(RX0::is_nullable && tail::is_nullable);
    enum { is_end = false };

    template<class InIt, class MATCHES>
    static bool do_match(InIt& it, const InIt& end, MATCHES& m)
    { 
        typedef typename MATCHES::match_container mc;
        typedef typename MATCHES::rx_unext rxun;
        if( tail::is_end ) {
            typedef _Sqmw<mc, rxun, _Norx> mw;
            return RX0::match(it,end,reinterpret_cast<mw&>(m));
        } else {
            typedef _Sqmw<mc, tail, rxun> mw;
            return RX0::match(it, end, reinterpret_cast<mw&>(m)) && tail::do_match(it,end,m);
        }
    }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt itbk(it);
        std::size_t nmbk = m.size();

        typedef typename MATCHES::match_container mc;
        typedef typename MATCHES::rx_next rxn;
        typedef _Sqmw<mc, _Norx, rxn> mw;    
        bool res = do_match(it, end, reinterpret_cast<mw&>(m));

        if( !res ) { it = itbk;    set_match_count(m,nmbk); }
        return res;
    }
};
template<> struct seq<_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe> {
    _SRX_NULLABLE(true);
    enum { is_end = true };
    template<class InIt, class MATCHES> 
    static bool do_match(InIt& it, const InIt& end, MATCHES& m)
        { return true; }
};

/**\ingroup grpSRXO
Alternative - like \c "(abc|def)"
\param RX0-RX9 regular expression class*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct alt {
    typedef alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,_Sqe> tail;

    _SRX_NULLABLE(RX0::is_nullable || tail::is_nullable);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt rxit(it); 
        std::size_t nmbk = m.size(), rxnm = nmbk;
        
        bool res = RX0::match(rxit,end,m);
        if( res ) rxnm = m.size();
        res |= tail::match(it,end,m);

        if( it < rxit || it == rxit ) {
            it = rxit;
            set_match_count(m,rxnm);
        } else
        if( res ) {
            std::size_t delta = rxnm - nmbk;
            if( delta ) {
                std::size_t count = m.size() - rxnm;
                for( ; count; ++nmbk, --count )
                    get_match_at(m,nmbk) = get_match_at(m,nmbk+delta);
                set_match_count(m,m.size()-delta);
            }
        }
        return res;
    }
};
template<> struct alt<_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe> {
    _SRX_NULLABLE(false);
    template<class InIt, class MATCHES> static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return false; }
};

/**\ingroup grpSRXO
Submatch marker
\param ID match identifier
\param RX regular expression to capture into match container
\sa 
    match - class used to capture single %match \n
    match_array - %match container based on static array \n
    match_vector - %match container based on std::vector*/
template<rx_int ID, class RX>
struct mark {
    _SRX_NULLABLE(RX::is_nullable);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt first(it);
        std::size_t nmbk = m.size();
        set_match_count(m,m.size()+1);
        bool res = RX::match(it,end,m);
        if( res && first != it ) {
            typedef typename MATCHES::match_type mt;
            get_match_at(m,nmbk) = mt(ID,first,it);
        } else
            set_match_count(m,nmbk);
        return res;
    }
};

/**\ingroup grpSRXO
Backreference - like <code>"(sense|response) and \\1bility"</code>
\param ID match identifier to refer*/
template<rx_int ID>
struct bk {
    _SRX_NULLABLE(true);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        typename MATCHES::iterator r = m.end();
        if( r == m.begin() ) return false;
        while( true ) {
            if( ID == (--r)->id() ) break;
            if( r == m.begin() ) return false;
        }

        InIt tend( it + (r->end() - r->begin()) );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it), s(r->begin());
        while( s < r->end() )    {
            if( *s != *t ) return false;
            ++s; ++t;
        }
        it = t;
        return true;
    }
};

/**\ingroup grpSRXO
non-greedy version of operator \c star<> */
template<class RX>
struct xstar:star<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        typedef typename MATCHES::rx_next rx_next;
        do {
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( rx_next::match(t,end,m) )
                { set_match_count(m,nmbk); break; }
        } while( RX::match(it,end,m) );
        return true;
    }
};

template<class RX>
struct xxstar:star<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        typedef typename MATCHES::rx_next rx_next;
        std::size_t next_nm;
        bool here_matched, next_matched=false;
        InIt next_pos(it);
        do {
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( here_matched = rx_next::match(t,end,m) ) {
                next_matched = true;
                next_pos = it;
                set_match_count(m,next_nm = nmbk);
            }
        } while( RX::match(it,end,m) );
        if( !here_matched && next_matched ) 
            { it = next_pos; set_match_count(m,next_nm); }
        return true;
    }
};

/**\ingroup grpSRXO
non-greedy version of operator \c plus<> */
template<class RX>
struct xplus:plus<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::match(it,end,m) && xstar<RX>::match(it,end,m); }
};

template<class RX>
struct xxplus:plus<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::match(it,end,m) && xxstar<RX>::match(it,end,m); }
};

/**\ingroup grpSRXO
non-greedy version of operator \c rep<>*/
template<std::size_t N1, std::size_t N2, class RX>
struct xrep:rep<N1,N2,RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        if( !rep<N1,N1,RX>::match(it,end,m) )
            return false;

        typedef typename MATCHES::rx_next rx_next;
        std::size_t n = N2 - N1;
        do {
            if( 0 == n-- ) break;
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( rx_next::match(t,end,m) )
                { set_match_count(m,nmbk); break; }
        } while( RX::match(it,end,m) );
        return true;
    }
};

template<std::size_t N1, std::size_t N2, class RX>
struct xxrep:rep<N1,N2,RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        if( !rep<N1,N1,RX>::match(it,end,m) )
            return false;

        typedef typename MATCHES::rx_next rx_next;
        std::size_t next_nm;
        bool here_matched = true, next_matched = false;
        InIt next_pos(it);
        std::size_t n = N2 - N1;
        do {
            if( 0 == n-- ) break;
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( here_matched = rx_next::match(t,end,m) ) {
                next_matched = true;
                next_pos = it;
                set_match_count(m,next_nm = nmbk);
            }
        } while( RX::match(it,end,m) );
        if( !here_matched && next_matched ) 
            { it = next_pos; set_match_count(m,next_nm); }
        return true;
    }
};

//-////////////////////////////////////////////////////////////////////////
/**\ingroup grpSRXO
\link static_regex::star star\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct star_:star<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xstar xstar\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xstar_:xstar<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xxstar xxstar\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xxstar_:xxstar<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::plus plus\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct plus_:plus<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xplus xplus\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xplus_:xplus<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xxplus xxplus\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xxplus_:xxplus<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::rep rep\endlink operator with multiple arguments*/
template<
    std::size_t N1, std::size_t N2,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct rep_:rep<N1,N2,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xrep xrep\endlink operator with multiple arguments*/
template<
    std::size_t N1, std::size_t N2,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xrep_:xrep<N1,N2,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xxrep xxrep\endlink operator with multiple arguments*/
template<
    std::size_t N1, std::size_t N2,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xxrep_:xxrep<N1,N2,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::opt opt\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct opt_:opt<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::mark mark\endlink operator with multiple arguments*/
template<
    rx_int ID,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct mark_:mark<ID,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

//-////////////////////////////////////////////////////////////////////////
// Often-used primitives
template<bool INCLUSIVE> struct ws_:cc<INCLUSIVE, ' ', '\t'>{};
struct ws:ws_<true>{};

template<bool INCLUSIVE> struct digit_:cr<'0','9',INCLUSIVE>{};
struct digit:digit_<true>{};

template<bool INCLUSIVE> struct xdigit_:cs< cr<'0','9',INCLUSIVE>, cr<'A','F',INCLUSIVE>, 
cr<'a','f',INCLUSIVE> >{};
struct xdigit:xdigit_<true>{};

template<bool INCLUSIVE> struct alpha_:cs< cr<'A','Z',INCLUSIVE>, cr<'a','z',INCLUSIVE> >{};
struct alpha:alpha_<true>{};

template<bool INCLUSIVE> struct alphanum_:cs< alpha_<INCLUSIVE>, digit_<INCLUSIVE> >{};
struct alphanum:alphanum_<true>{};

struct eol:seq<opt<c<'\r'> >, c<'\n'> >{};

struct eos {
    _SRX_NULLABLE(true);
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return it == end; }
};

struct dot {
    _SRX_NULLABLE(false);
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return (it != end) ? (++it, true) : false; }
};

//-////////////////////////////////////////////////////////////////////////
template<class IT> class _NoMatches {
    _NoMatches() {}
public:
    typedef submatch<IT> match_type;
    typedef const match_type* iterator;
    typedef _NoMatches match_container;
    typedef _Norx rx_unext;
    typedef _Norx rx_next;
public:
    std::size_t size() const { return 0; }
    iterator begin() const { return 0; }
    iterator end() const { return 0; }
    static _NoMatches<IT>& _Get() { static _NoMatches<IT> m; return m; }
};

template<class IT>
void set_match_count(_NoMatches<IT>& m, std::size_t cnt)
    {}

template<class IT>
submatch<IT> get_match_at(_NoMatches<IT>& m, std::size_t pos)
    { return submatch<IT>(); }

template<class M> struct _Mmw:M {
    typedef _Mmw match_container;
    typedef _Norx rx_unext;
    typedef _Norx rx_next;
};

template<class RX, class InIt>
inline bool match(InIt& it, const InIt& end)
    { return RX::match(it,end, _NoMatches<InIt>::_Get()); }

template<class RX, class InIt, class MATCHES>
inline bool match(InIt& it, const InIt& end, MATCHES& m)
{ 
    typedef _Mmw<MATCHES> mw;
    return RX::match(it,end,reinterpret_cast<mw&>(m.reset())); 
}

}//namespace static_regex

#undef _SRX_NULLABLE
#endif//__STATIC_REGEX_H_INCLUDED__
Re[2]: Код: версия 0.00000004 - изменения
От: Аноним  
Дата: 06.01.04 19:16
Оценка:
-переименования
-- range<> --> cr<> (мнемоника — "char range")
-- set<> --> cs<> (мнемоника — "char sange")
-- select<> --> mark<> (конфликты с gcc)

-убраны операторы начинающиеся с "not_" — вместо них используйте "name_<false", где "name" — имя оператора. Например not_cc<A,B,C> == cc_<false,A,B,C>

-добавлены многоаргументные версии для всех нетерминальных операторов (т.е. star, plus, opt, и тд) — их имена также заканчиваются на "_"

-у оператора захвата подсовпадения mark<int ID, class RX> появился параметр ID — это произвольный числовой идентификатор подсовпадения.

-Нельзя пользоваться member-функцией RX::match() — она стала насколько мохнатой, что пришлось ввести глобальные функции match().
Их надо использовать так:
static_regex::match_array<> matches;
bool matched = static_regex::match<myregex>(start, end, matches);//или..
bool matched = static_regex::match<myregex>(start, end);//или..


-Теперь библиотека использeт контейнеры для хранения подсовпадений. Доступно 2 вида контейнеров:
-- match_array<class InIt,int N> — контейнер основанный на статическом массиве размера N. Если подсовпадений больше чем размер контейнера, то "лишние" подсовпадения игнорируются.
-- match_array<class InIt> — контейнер основанный на std::vector<>.
-- более подробно, смотрите эти классы и класс submatch в исходниках.
Пример использования:
template<class RX> void test(char* pp)
{
    typedef pxt::static_regex::match_array<char*>  MC;
//  typedef pxt::static_regex::match_vector<char*> MC;    
    MC mc;

    char* p = pp;
    bool res = pxt::static_regex::match<RX>(p, p+strlen(p), mc);
    printf("%smatched: %s\n", res?"":"not ", pp);
    if( res ) {
        printf("\t{%.*s}%s\n", p - pp, pp, p);    
        printf("\t");
        for(MC::iterator i=mc.begin(); i!=mc.end(); ++i)
            printf("{%d:%.*s}", i->id(), i->length(), i->begin());    
        printf("\n");
    }
}


-Добавлен оператор "обратной ссылки" bk<int ID>
Пример использования (псевдокод)
typedef seq<mark<1,cc<'\'','"'>>, s<"HELLO">, bk<1>> myrx;
//myrx совпадет со строкой "HELLO" и со строкой 'HELLO'


-к ранее имевшимся "тупым" операторам-повторителям star<>, plus<>, rep<> добавлены следующие их модификации:
-- "нежадные": xstar<>, xplus<>, xrep<>
Пример использования (псевдокод)
typedef seq<mark<1,plus<dot>>, mark<2,s<".cpp">>>  myrx1;
typedef seq<mark<1,xplus<dot>>, mark<2,s<".cpp">>> myrx2;
//myrx2 совпадет со строкой "file1.cpp", а myrx1 - нет, 
//т.к. оператор plus<dot> сьест все до конца строки.

-- "жадные": xxstar<>, xxplus<>, xxrep<>
Пример использования (псевдокод)
typedef seq<mark<1,xxplus<dot>>, mark<2,s<".cpp">>> myrx3;
//при проверке строки "file1.cpp.cpp.cpp.cpp"
//myrx2 совпадет с подстрокой "file1.cpp", а myrx3 - с полной строкой,

Внимание: использование этих модификаций влечет за собой значительное падение производительности. "нежадных" — примерно в 2 раза, "жадных" — в десятки раз.

-Бенчмарки
Не улучшились, но и не ухудшились.
Был также проведен тест на производительность "жадных" операторов.
выражение "(.+)(\.cpp)" проверялось на строке "file.cpp.cpp.cpp.cpp" длиной 4 мегабайта. boost::regex оказалась хуже в 10 раз...
Re[3]: Код: версия 0.00000004 - изменения
От: Аноним  
Дата: 07.01.04 06:54
Оценка:
Здравствуйте, Аноним, Вы писали:

А>-переименования

А>-- set<> --> cs<> (мнемоника — "char sange")

Хмм, sange...

Keep up good work
Re[2]: Некоторые замечания по коду 4
От: Tonal- Россия www.promsoft.ru
Дата: 29.01.04 23:25
Оценка:
Наверное надо включить #include <vector> если есть элементы зависимые от std::vector.

Не совсем понятно назначение функций get_match_at и set_match_count. Почму нельзя просто воспользоваться методами operator[]() и resize(). Тогда не понадобятся friend объявления, которые во первых не совсем тривиальны для шаблонов, а во вторых разные компиляторы их по разному трактуют (Borland например требует полной спецификации шаблонных параметров.)

По моему operator[]() для match_vector и для match_array несколько расходятся. Если уж проверять выход за граници, то для обоих, или уж не проверять совсем. А так как-то не согласованно получается.
Я бы не проверял (по крайний мере в релизе).

Начитался давеча Саттера — он говорит что не следует применять наследование без вестких на то причин — это я о match_vector. Собственно если переименовать функцию reset() в clear() то вместо match_vector можно будет использовать и std::vector, и std::deque и boost::array. В общем непонятна суть ограничений.

Есть некоторый недостаток в ID к mark-у: непонятно как избежать совподения. Оно может случиться не только из за ошибок набивки, но и в случаи собирания выражения из разных частей. ;-с

По моему было бы очень удобно, если для любого вырожения можно было бы получить максимальное количество подсовпадений. Реализация — тривиальна: для символьных классов = 0, для mark = подвырожение + 1, для контейнеров = сумма подвырожений.

Может быть следует предоставить 2 формы alt — полный перебор (POSIX-like), или до первого совпадения (Perl-like) — некоторые выражения можно соптимизировать.

Ну вроде на первый взгляд всё, спать пора. ;-в
... << RSDN@Home 1.1.0 stable >>
Re[3]: Некоторые замечания по коду 4
От: Аноним  
Дата: 02.02.04 14:01
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Наверное надо включить #include <vector> если есть элементы зависимые от std::vector.

Это я недоглядел.
Данныай файл включен в более развесистую либу, где с вектором разбираются вполне отдельно.
Впрочем, включение <vector> и не надо — достаточно forward-declaration.

T>Не совсем понятно назначение функций get_match_at и set_match_count. Почму нельзя просто воспользоваться методами operator[]() и resize().

Эти функци реализуют дополнительный контейнеро-независимый уровень абстракции.
Читай ниже — поймешь.

T>а во вторых разные компиляторы их по разному трактуют (Borland например требует полной спецификации шаблонных параметров.)

Есть только одна трактовка — стандарт C++. Если компилятор стандарт не понимает, то идет он пусть в /dev/nul

T>По моему operator[]() для match_vector и для match_array несколько расходятся. Если уж проверять выход за граници, то для обоих, или уж не проверять совсем.

Гм. А где я проверяю границы? Это отадно на откуп реализации контейнера.

T>Начитался давеча Саттера — он говорит что не следует применять наследование без вестких на то причин — это я о match_vector.

T>Собственно если переименовать функцию reset() в clear() то вместо match_vector можно будет использовать и std::vector, и std::deque и boost::array.
T>В общем непонятна суть ограничений.
Суть в том, что требуется обьект способный принимать и хранить подсовпадения.
Для этого был сделан match_array который описывает в описывает минимальные требования к
контейнеру подсовпадений. И уже потом, был добавлен match_vector который аналогичен match_array.
В общем, я согласен с твоим замечанием, что match_vector слишком исскуственно ограничен и можно хранить подсовпадения в любом контейнере который удовлетворяет требованиям "Sequence".
Но это ты как-нибудь сам реализуй
Работы, сосно гря немного:
— переименовать reset() в clear()
— переименовать match_type в value_type
— реализовать get_match_at и set_match_count для контейнеров других типов.

T>Есть некоторый недостаток в ID к mark-у: непонятно как избежать совподения.

В смысле, как избежать совпадения ID у двух разных mark-ов ?
А никак — да и ненужно — раз усер дал разным mark-ам одинаковый ID, то этого он и хотел

T>По моему было бы очень удобно, если для любого вырожения можно было бы получить максимальное количество подсовпадений. Реализация — тривиальна: для символьных классов = 0, для mark = подвырожение + 1, для контейнеров = сумма подвырожений.

Не вижу смысла. Количество подвыражений — функция входной строки, а не регулярного выражения. Вина этому — операторы-повторители.

Например, выражение "(a)*" на строке "aaaaaaaaaaa" даст очень много подвыражений, а на строке "bbbbbb" ни одного

T>Может быть следует предоставить 2 формы alt — полный перебор (POSIX-like),

Этот вариант реализован.

T>или до первого совпадения (Perl-like) — некоторые выражения можно соптимизировать.

Опять-таки: не вижу смысла. Оптимизация такого рода — задача усера. Например, если он напишет
выражение "(.*this|.*that|.*there)" — ежу понятно насколько быстрым будет такое варажение и как его оптимизировать

T>Ну вроде на первый взгляд всё, спать пора. ;-в

Нухшо, словечко "вырожение" от которого меня просто трясет и хочется кого-нибудь спишем на то что тебе спать очень хочется
Re: SRC: boost::(spirit|regex) для бедных
От: Дарней Россия  
Дата: 21.10.05 10:50
Оценка:
интересно, кто-нибудь знает, как работают POSIX NFA движки? Используют двухстековый метод? А как там решается проблема с "ленивыми" квантификаторами?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[2]: SRC: boost::(spirit|regex) для бедных
От: 0xDEADBEEF Ниоткуда  
Дата: 27.10.05 12:46
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>интересно, кто-нибудь знает, как работают POSIX NFA движки? Используют двухстековый метод?

Смотрел gnu regex, там вообще "классические" автоматы не используются.
Генерируется какой-то псевдокод, который потом интерпретируется.
Что-то подобное происходит и в boost::regex, но я там глубоко не копался.

Дело в том, что посредством автоматов некоторые вещи (маркирование подвыражений, обратные ссылки) сделать достаточно трудно, если не невозможно. По крайней мере, мне не удалось на автомате реализовать обратные ссылки.

Д>А как там решается проблема с "ленивыми" квантификаторами?

Для недетерминированного автомата — это вообще не проблема. Он может быть "уступчивым", а может быть "жадным" в зависимости от того, что предпринимать, если в текущем наборе альтернатив есть финальное состояние.

Есть такие варианты:
(1) останавливаемся, несмотря на то, что есть "не финальные" альтернативы. Получим наикратчайшее совпадение — автомат будет "уступчивым"
(2) продложаем, пока финальное состояние не будет единственным в наборе альтернатив. Получим наидлиннейшее совпадение — автомат будет "жадным"
__________
16.There is no cause so right that one cannot find a fool following it.
Re[3]: SRC: boost::(spirit|regex) для бедных
От: Дарней Россия  
Дата: 28.10.05 04:50
Оценка:
Здравствуйте, 0xDEADBEEF, Вы писали:

DEA>Дело в том, что посредством автоматов некоторые вещи (маркирование подвыражений, обратные ссылки) сделать достаточно трудно, если не невозможно. По крайней мере, мне не удалось на автомате реализовать обратные ссылки.


верно, некоторые вещи сделать нельзя. еще есть проблемы с метасимволами, насколько я понимаю
но можно попробовать прикрутить дополнительные фичи поверх автомата

DEA>Есть такие варианты:

DEA>(1) останавливаемся, несмотря на то, что есть "не финальные" альтернативы. Получим наикратчайшее совпадение — автомат будет "уступчивым"
DEA>(2) продложаем, пока финальное состояние не будет единственным в наборе альтернатив. Получим наидлиннейшее совпадение — автомат будет "жадным"

а если внутри выражения есть несколько квантификаторов для разных его частей, из них один "жадный" а другой "ленивый"?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re: SRC: boost::(spirit|regex) для бедных
От: _nn_ www.nemerleweb.com
Дата: 30.10.05 16:57
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

Что-то не получилось воспользоваться кодом на ваших примерах.

Может есть более новая версия чем 4 ?
Если 4 это последняя, приведите пожалуйста небольшие примеры которые работают для 4-й версии.

Спасибо.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: SRC: boost::(spirit|regex) для бедных
От: Дарней Россия  
Дата: 06.11.05 11:57
Оценка:
Здравствуйте, 0xDEADBEEF, Вы писали:

DEA>C метасимволами как раз проблемы нету. Конечно, если автомат NFA. Просто трактуешь этот метасимвол как "простой" символ — и при двустековом моделировании он отработает нормально. А вот для DFA — метасимволы — это пипец полный — в особенности если алфавит — юникодный — автомат разрастается до поистине ненормальных размеров.


не совсем понял. вставлять их во входной поток, наравне с обычными символами?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.