Страница 2 из 2

Re: регулярные выражения в C/C++

Добавлено: 14 сен 2016, 12:39
Olej
Olej писал(а):Здесь вот онлайновый тестер регулярных выражений, который позволяет проверить результат сопоставления, без написания какого-либо программного кода и не используя никакие GNU утилиты: Regex Pal.
Очень удобно при отработке.
И ещё:
RegExrv2.1

И ещё:
0.3.1b built by gskinner.com

Но самое смешное, так это что регулярные выражения, сопоставляются в одном из таких онлайнов, а также grep, egrep и др. - не сопоставляются во всех остальных и наоборот. :-o :-(
В этом смысле показательна фраза (стр.12) из книги Майкла Фицджеральда:
Большинство из указанных реализаций регулярных выражений в чем-то сходны, а в чем-то различаются. Я не могу подробно обсудить все отличия в столь маленькой кни­ге, но о многих расскажу. Любые попытки задокументировать все различия между все­ ми реализациями наверняка привели бы меня в больницу.
:lol:

Re: регулярные выражения в C/C++

Добавлено: 18 ноя 2016, 23:11
Olej
Сами регулярные выражения, перед их внесением в код C/C++ хорошо бы проверять (отлаживать) ... хотя бы просто потому, что регулярные выражения - уж точно "не фишка" C/C++, не самое сильное место этих языков.
Для этого хорошо бы иметь под рукой тестовый инструмент регулярных выражений.
Я предлагаю использовать в этом качестве sed - потоковый текстовый редактор.
И в упоминаемой там книге Краткий учебник по sed есть Глава 2 - вполне достаточное введение в технику регулярных выражений.

Re: регулярные выражения в C/C++

Добавлено: 13 май 2017, 09:46
Olej
Не прошло и пол-года, как возникла ещё раз оказия порепетировать с регулярными выражениями C++, в связи с вот этой проблемой: интерпретатор программного кода (на C++). Но с регулярными выражениями (на любом инструменте их использования: Perl, Python, Ruby, sed, awk, grep, egrep, ...) проблема состоит в том, что для синтаксиса регулярных выражений существует 10000000 стандартов граматики, и никогда не знаешь деталей того, который сейчас используешь.
Вот так же и с библиотекой regex C++:
- она новая, появилась только в стандарте C++11 (2011г.)
- нигде толком не описана (в деталях граматик)
- при создании объектов регулярных выражений можно указать константой в конструкторе 5 (как минимум) различающихся граматик:
basic Basic POSIX grammar
extended Extended POSIX grammar
awk Awk POSIX grammar
grep Grep POSIX grammar
egrep Egrep POSIX grammar
- мелкие детали того, что они понимают под каждой, нигде не описано. :-(

Хоть вот это ;-) : syntax specifications std::ECMAScript syntax
The following syntax is used to construct regex objects (or assign) that have selected ECMAScript as its grammar.

Re: регулярные выражения в C/C++

Добавлено: 12 дек 2017, 17:01
Olej
Olej писал(а):
Olej писал(а):P.S. В приложении - все сразу показанные до сих пор примеры.
Дальнейшие редакции этого текста (дополнения, изменения, исправления, ...) см. здесь: Регулярные выражения C/C++
Регулярные выражения в С++ с блеском показали себя на 2-х проектах:
интерпретатор программного кода (на C++)
симулятор процессора
Особенно во 2-м!
Синтаксический разбор языка ассемблера, который мог бы делаться неделями или даже месяцами, был прописан в 3 дня работы.

Re: регулярные выражения в C/C++

Добавлено: 12 дек 2017, 17:18
Olej
Olej писал(а): Особенно во 2-м!
Синтаксический разбор языка ассемблера, который мог бы делаться неделями или даже месяцами, был прописан в 3 дня работы.
Но во всех задачах подбирать вид регулярного выражения - занятие тягомутное и трудоёмкое.
Чтоб его сделать простым и быстрым, сделано такое приложение regc.cc :
- считывает любое число строк-патернов (регулярных шаблонов) из отдельного файла, расширения .pat
- потом в диалоге прогоняющем все вводимые строки на результат отождествления c этими патернами.

Код: Выделить всё

#include <iostream>
#include <fstream>
#include <regex>
using namespace std;

inline regex pattern( const string& r ) {
   //   try { return regex( r ); }                     // с учётом регистра
   try { return regex( r, regex_constants::icase ); }  // без учёта регистра
   catch( regex_error& e ) {                           // ошибка записи регулярного выражения
      cerr << "синтаксис регулярного выражения:\t" << r << endl;
      exit( 3 );
   }
}
// static constexpr flag_type basic = regex_constants::basic;
// static constexpr flag_type extended = regex_constants::extended;
// static constexpr flag_type awk = regex_constants::awk;
// static constexpr flag_type grep = regex_constants::grep;

int test_table( int p, char* fname[] ) {
   while( --p ) {
      ifstream fin;
      fin.open( fname[ p ] ); 
      if( !fin ) break;
      fin.close();
   }
   return p; 
}

vector<regex> load_table( int p, char* fname[] ) { 
   vector<regex> vr;
   int n = 1;
   while( --p ) {
      ifstream fin;
      string cur;
      fin.open( fname[ p ] ); 
      while( true ) {              
         getline( fin, cur );
         if( fin.eof() ) break;                        // EOF
         if( '#' == cur[ 0 ] ) continue;               // комментарий
         if( !cur.length() ) continue;                 // пустая строка
         try { 
            regex rc = regex( cur );
            vr.push_back( rc );
            cout << "#" << n++ << ":\t" << cur << endl;
         }
         catch( regex_error& e ) {                     // ошибка трансляции регулярного выражения
            cout << "ошибка:\t" << cur << endl;
         }
      }
      fin.close();
   }      
   cout << "-------------------------------------------" << endl;
   return vr;
}

int main( int argc, char *argv[] ) {
   if( argc < 2 ) {
       cout << "не заданы файлы щаблонов?" << endl;
       return 1;
   }
   int n = test_table( argc, argv );
   if( n ) {
      cout << "файл шаблонов не найден: " << argv[ n ] << endl;      
      return 2;
   }
   vector<regex> r = load_table( argc, argv );
   smatch m;
   while( true ) { 
      cout << "> ";
      string cur;
      getline( cin, cur );
      if( cin.eof() ) {
         cout << endl;
         return 0; 
      }
      if( cur == "!" || cur == "~" ) {
         r = load_table( argc, argv );
         continue;
      }
      n = 1;
      for( auto &pt : r ) { 
         if( regex_match( cur, m, pt ) ) {
            cout << "#" << n << " [" << m.size() << "]: " << m[ 0 ].str() << " => " << endl;
            for( unsigned i = 1; i < m.size(); i++ )
               cout << i << ": [" << m[ i ].str() << "] <" << m.position( i ) << ":" 
                    << m.length( i ) << ">" << endl;
         }
         n++;
      }
   }
}

Re: регулярные выражения в C/C++

Добавлено: 12 дек 2017, 17:27
Olej
Olej писал(а): Но во всех задачах подбирать вид регулярного выражения - занятие тягомутное и трудоёмкое.
Чтоб его сделать простым и быстрым, сделано такое приложение regc.cc :
- считывает любое число строк-патернов (регулярных шаблонов) из отдельного файла, расширения .pat
- потом в диалоге прогоняющем все вводимые строки на результат отождествления c этими патернами.
Выглядеть это может примерно так ... чтобы долго не объяснять:

Код: Выделить всё

[olej@dell 3]$ ./regs cmd.pat
#1:     ^\s*(nop)\s*$
#2:     ^\s*(halt)\s*$
#3:     ^\s*(rrmovl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*,\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#4:     ^\s*(irmovl)\s+(\w+|\$[\+|\-]?[0-9]+|\$0x[0-9|a-f]+)\s*,\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#5:     ^\s*(rmmovl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*,\s*([\+|\-]?[0-9]+|0x[0-9|a-f]+)*\s*\(\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*\)\s*$
#6:     ^\s*(mrmovl)\s+([\+|\-]?[0-9]+|0x[0-9|a-f]+)*\s*\(\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*\)\s*,\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#7:     ^\s*(addl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*,\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#8:     ^\s*(subl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*,\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#9:     ^\s*(andl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*,\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#10:    ^\s*(xorl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*,\s*%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#11:    ^\s*(jmp)\s+(\w+)\s*$
#12:    ^\s*(jle)\s+(\w+)\s*$
#13:    ^\s*(jl)\s+(\w+)\s*$
#14:    ^\s*(je)\s+(\w+)\s*$
#15:    ^\s*(jne)\s+(\w+)\s*$
#16:    ^\s*(jge)\s+(\w+)\s*$
#17:    ^\s*(jg)\s+(\w+)\s*$
#18:    ^\s*(call)\s+(\w+)\s*$
#19:    ^\s*(ret)\s*$
#20:    ^\s*(pushl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
#21:    ^\s*(popl)\s+%e(ax|cx|dx|bx|sp|bp|si|di)\s*$
-------------------------------------------
> nop
#1 [2]: nop =>
1: [nop] <0:3>
> halt
#2 [2]: halt =>
1: [halt] <0:4>
> rrmovl %eax , %ebx
#3 [4]: rrmovl %eax , %ebx =>
1: [rrmovl] <0:6>
2: [ax] <9:2>
3: [bx] <16:2>
> irmovl array , %edx
#4 [4]: irmovl array , %edx =>
1: [irmovl] <0:6>
2: [array] <7:5>
3: [dx] <17:2>
> irmovl $4 , %esi
#4 [4]: irmovl $4 , %esi =>
1: [irmovl] <0:6>
2: [$4] <7:2>
3: [si] <14:2>
> irmovl $-10 , %esi
#4 [4]: irmovl $-10 , %esi =>
1: [irmovl] <0:6>
2: [$-10] <7:4>
3: [si] <16:2>
> rmmovl  %ecx , -3(%ebx)
#5 [5]: rmmovl  %ecx , -3(%ebx) =>
1: [rmmovl] <0:6>
2: [cx] <10:2>
3: [-3] <15:2>
4: [bx] <20:2>
> rmmovl %esp, 0x12345 (%edx)
#5 [5]: rmmovl %esp, 0x12345 (%edx) =>
1: [rmmovl] <0:6>
2: [sp] <9:2>
3: [0x12345] <13:7>
4: [dx] <24:2>
> mrmovl (%edx), %eax
#6 [5]: mrmovl (%edx), %eax =>
1: [mrmovl] <0:6>
2: [] <19:0>
3: [dx] <10:2>
4: [ax] <17:2>
> mrmovl 8(%ebp), %edx
#6 [5]: mrmovl 8(%ebp), %edx =>
1: [mrmovl] <0:6>
2: [8] <7:1>
3: [bp] <11:2>
4: [dx] <18:2>
> mrmovl -12(%ebp), %edx
#6 [5]: mrmovl -12(%ebp), %edx =>
1: [mrmovl] <0:6>
2: [-12] <7:3>
3: [bp] <13:2>
4: [dx] <20:2>
> mrmovl 0xf012( %eax ) , %ebx
#6 [5]: mrmovl 0xf012( %eax ) , %ebx =>
1: [mrmovl] <0:6>
2: [0xf012] <7:6>
3: [ax] <17:2>
4: [bx] <26:2>
> addl %eax , %ebx
#7 [4]: addl %eax , %ebx =>
1: [addl] <0:4>
2: [ax] <7:2>
3: [bx] <14:2>
>   subl %eax , %ebx
#8 [4]:   subl %eax , %ebx =>
1: [subl] <2:4>
2: [ax] <9:2>
3: [bx] <16:2>
>   andl %eax , %ebx
#9 [4]:   andl %eax , %ebx =>
1: [andl] <2:4>
2: [ax] <9:2>
3: [bx] <16:2>
>  xorl %eax , %ebx
#10 [4]:  xorl %eax , %ebx =>
1: [xorl] <1:4>
2: [ax] <8:2>
3: [bx] <15:2>
>  jmp yyyy
#11 [3]:  jmp yyyy =>
1: [jmp] <1:3>
2: [yyyy] <5:4>
>  jle yyyy
#12 [3]:  jle yyyy =>
1: [jle] <1:3>
2: [yyyy] <5:4>
> jl yyyy
#13 [3]: jl yyyy =>
1: [jl] <0:2>
2: [yyyy] <3:4>
> je yyyy
#14 [3]: je yyyy =>
1: [je] <0:2>
2: [yyyy] <3:4>
> jne yyyy
#15 [3]: jne yyyy =>
1: [jne] <0:3>
2: [yyyy] <4:4>
> jge yyyy
#16 [3]: jge yyyy =>
1: [jge] <0:3>
2: [yyyy] <4:4>
> jg yyyy
#17 [3]: jg yyyy =>
1: [jg] <0:2>
2: [yyyy] <3:4>
>   call xxxx
#18 [3]:   call xxxx =>
1: [call] <2:4>
2: [xxxx] <7:4>
>   ret
#19 [2]:   ret =>
1: [ret] <2:3>
>  pushl %ebp
#20 [3]:  pushl %ebp =>
1: [pushl] <1:5>
2: [bp] <9:2>
>  popl %ebp
#21 [3]:  popl %ebp =>
1: [popl] <1:4>
2: [bp] <8:2>
> ^C
Всё должно быть понятно!

Re: регулярные выражения в C/C++

Добавлено: 12 дек 2017, 18:11
Olej
Вопрос (задают!):
- почему сами строки регулярных выражений в примерах кода C++ записываем так ( R"(...)" ) :?: :

Код: Выделить всё

R"(^\s*(.align)\s+(1|2|4|8|16|32)\s*$)"
Ответ состоит в том, что в записи C/C++ (по синтаксису строк) экранирующий символ '\' нужно бы записывать 2 раза подряд: "\\d".
Например, для показанной выше строки шаблона: R"(^\s*(.align)\s+(1|2|4|8|16|32)\s*$)" - полностью эквивалент можно записать и так (сравнивайте):

Код: Выделить всё

"^\\s*(.align)\\s+(1|2|4|8|16|32)\\s*$"

Но при большом числе '\' в строке шаблона (а их всегда много) такая запись совсем не читабельная.

Это всё касается так называемого std::ECMAScript синтаксиса записи регулярных выражений.
Про это (и про синтаксис шаблонов ECMAScript) можете почитать здесь.
В <regex> можно изменять используемый синтаксис ... варианты:

Код: Выделить всё

string r = "...";            // шаблон
regex R = regex( r );  // по умолчанию, ECMAScript 
regex R = regex( r, regex_constants::icase ); // без учёта регистра
// static constexpr flag_type basic = regex_constants::basic; // варианты синтаксиса:
// static constexpr flag_type extended = regex_constants::extended;
// static constexpr flag_type awk = regex_constants::awk;
// static constexpr flag_type grep = regex_constants::grep;

Re: регулярные выражения в C/C++

Добавлено: 12 дек 2017, 20:52
Olej
Olej писал(а): Чтоб его сделать простым и быстрым, сделано такое приложение regc.cc :
- считывает любое число строк-патернов (регулярных шаблонов) из отдельного файла, расширения .pat
- потом в диалоге прогоняющем все вводимые строки на результат отождествления c этими патернами.
Ещё для тестирования регулярных выражений оказываются сильно полезны онлайн сервисы:

- https://regexr.ru/
r1.png
- https://regexr.com/
r2.png

Re: регулярные выражения в C/C++

Добавлено: 14 дек 2022, 03:25
Olej
Olej писал(а): Это всё касается так называемого std::ECMAScript синтаксиса записи регулярных выражений.
Про это (и про синтаксис шаблонов ECMAScript) можете почитать здесь.
Эта ссылка, кстати, является вполне достаточной справочной страницей по std::ECMAScript syntax, вполне достаточной для написания собственных патернов синтаксического разбора:
ECMAScript regular expressions pattern syntax
...
Special pattern characters
...
Quantifiers
...

Groups
(subpattern) Group Creates a backreference.
(?:subpattern) Passive group Does not create a backreference.

Assertions
...
Alternatives
...
Character classes
...
[:xdigit:] hexadecimal digit character isxdigit
...
Ну, и ещё вот это - public member function <regex>
std::regex_traits::lookup_classname:
...
alpha alphabetic character isalpha
blank blank character isblank
cntrl control character iscntrl
digit decimal digit character isdigit
graph character with graphical representation isgraph
lower lowercase letter islower
print printable character isprint
punct punctuation mark character ispunct
space whitespace character isspace
upper uppercase letter isupper
xdigit hexadecimal digit character isxdigit
...