SLRE: сверхлегкая библиотека обработки regex Печать
Добавил(а) microsin   

Еще один кандидат обработки регулярных выражений на микроконтроллерах - библиотека SLRE [1] (аббревиатура SLRE означает Super Light Regular Expression library). Возможно, этот вариант даже лучше, чем T-Rex [2]. Основное отличие от T-Rex в том, что меньше требуется места под код (5 килобайт вместо 8), и не используется динамическое выделение памяти malloc (вместо этого задействован стек). Автор библиотеки Sergey Lyubka (см. файл slre.h), он доброжелательно отвечает на вопросы, связанные с библиотекой. SLRE можно использовать на условиях лицензии GNU GPL v.2, также есть возможность покупки коммерческой лицензии, которая не предусматривает лицензионных отчислений. Здесь приведен перевод оригинальной документации SLRE, опубликованной на GitHub [1].

Код SLRE совместим со стандартом ISO C / ANSI C'89. Библиотека SLRE реализует проверку подмножества синтаксиса регулярных выражений Perl. В частности, не поддерживаются фигурные скобки, позволяющие точно задавать количество повторений в регулярном выражении.

Библиотека легко расширяется. Например, если Вам нужно добавить новый метасимвол \i, означающий IP-адрес IPv4, то с помощью SLRE это сделать просто. SLRE отлично справляется с задачами обработки сетевых запросов, файлов конфигурации, консольного ввода пользователя (командной строки) и т. п. Библиотеку SLRE целесообразно применять в тех местах, где библиотеки наподобие PCRE становятся слишком ресурсоемким выбором - разработчики встраиваемых систем получат при использовании SLRE наибольшее преимущество.

[Синтаксис, поддерживаемый SLRE]

^       Совпадение с началом строки.

$       Совпадение с концом строки.

()      Группирование символов проверяемого текста с целью извлечения его фрагментов (substring capturing).

\s      Совпадение с пробелом.

\S      Совпадение с любым символом, не совпадающим с пробелом.

\d      Совпадение с десятичной цифрой.

\n      Совпадение с символом перехода на новую строку (LF).

\r      Совпадение с символом возврата каретки (CR).

\f      Совпадение с символом перевода страницы (FF).

\v      Совпадение с символом вертикальной табуляции.

\t      Совпадение с символом горизонтальной табуляции (TAB).

\b      Совпадение с символом backspace.

+       Совпадение в одно или большее количество раз (жадный режим обработки).

+?      Совпадение в одно или большее количество раз (не жадный, или ленивый режим).

*       Совпадение ноль или большее количество раз (жадный режим обработки).

*?      Совпадение ноль или большее количество раз (не жадный, или ленивый режим).

?       Совпадение совпадение ноль или один раз (не жадный, или ленивый режим).

x|y     Совпадение с x или с y (оператор вариантов ИЛИ).

\meta   Совпадение с одним из метасимволов: ^$().[]*+?|\ (экранирование специальных символов).

\xHH    Совпадение с байтом, указанным в hex-формате, например \x4a (0x4A).

[...]   Совпадение любым символом из набора. В квадратных скобках перечисляются символы для совпадения, или задается их диапазон наподобие [a-z].

[^...]  Совпадение с любым символом, который не входит в указанный набор.

В жадном режиме (по умолчанию) алгоритм регулярных выражений ищет соответствие квантификатору настолько много раз, насколько это возможно. Обратный этому ленивый режим, он проверяет соответствие минимальное количество раз. Подробнее см. [3].

[Как применять библиотеку SLRE]

API библиотеки чрезвычайно простой. Это единственная функция slre_match, которая обнаруживает совпадение, и структура slre_cap, которая предназначена для выборок из регулярного выражения (фрагментов проверяемого текста, обозначенных в регулярном выражении круглыми скобками).

struct slre_cap {
  char *ptr;
  int len;
};
 
int slre_match(char *regexp, char *buf, int buf_len,
               struct slre_cap *caps, int num_caps, int flags);

regexp указатель на строку ASCIIZ, в которой записано регулярное выражение.

buf указатель на проверяемую строку текста (она проверяется на соответствие с регулярным выражением).

buf_len длина строки проверяемой текста в байтах.

caps ссылка на массив структур slre_cap. В этом массиве должно быть столько же элементов, сколько в регулярном выражении встречается пар круглых скобок. Если одна пара круглых скобок, то это может быть указатель на один объект slre_cap.

num_caps количество пар круглых скобок (должно быть равно количеству элементов массива caps).

flags флаги, которые учитываются при обработке строки на соответствие регулярному выражению. Пока что поддерживается единственный флаг SLRE_IGNORE_CASE, который включает игнорирование регистра символов текста проверяемой строки (маленькие буквы считаются эквивалентными большим).

Функция slre_match вернет количество обработанных байт проверяемой строки от её начала. Если возвращенное значение значение больше или равно 0, то было обнаружено совпадение строки с регулярным выражением. Если же возвращено отрицательное значение, то это означает ошибку (совпадение не обнаружено). Возвращаемые коды ошибки:

#define SLRE_NO_MATCH               -1    //совпадение не обнаружено
#define SLRE_UNEXPECTED_QUANTIFIER  -2    //неожиданный квантификатор, т. е. *, +, ?, { и }
#define SLRE_UNBALANCED_BRACKETS    -3    //непарные круглые скобки
#define SLRE_INTERNAL_ERROR         -4    //внутренняя ошибка
#define SLRE_INVALID_CHARACTER_SET  -5    //недопустимый набор символов
#define SLRE_INVALID_METACHARACTER  -6    //недопустимый метасимвол, т. е. \, ^, $ и т. д.
#define SLRE_CAPS_ARRAY_TOO_SMALL   -7    //массив для фрагментов слишком мал
#define SLRE_TOO_MANY_BRANCHES      -8    //слишком много ветвлений
#define SLRE_TOO_MANY_BRACKETS      -9    //слишком много скобок

Пример обработки запроса HTTP:

const char *request = " GET /index.html HTTP/1.0\r\n\r\n";
struct slre_cap caps[4];
 
if (slre_match("^\\s*(\\S+)\\s+(\\S+)\\s+HTTP/(\\d)\\.(\\d)",
               request, strlen(request), caps, 4, 0) > 0) {
  printf("Метод: [%.*s], URI: [%.*s]\n",
         caps[0].len, caps[0].ptr,
         caps[1].len, caps[1].ptr);
} else {
  printf("Ошибка обработки [%s]\n", request);
}

Пример поиска ссылок URL в строке:

static const char *str =
  "< img src=\"HTTPS://FOO.COM/x?b#c=tab1\"/> "
  "  < a href=\"http://cesanta.com\" >some link< /a>";
 
static const char *regex = "((https?://)[^\\s/'\"< >]+/?[^\\s'\"< >]*)";
struct slre_cap caps[2];int i, j = 0, str_len = strlen(str);
 
while (j < str_len &&
       (i = slre_match(regex, str + j, str_len - j, caps, 2, SLRE_IGNORE_CASE)) > 0) {
  printf("Найден URL: [%.*s]\n", caps[0].len, caps[0].ptr);
  j += i;
}

Вывод:

Найден URL: [HTTPS://FOO.COM/x?b#c=tab1]
Найден URL: [http://cesanta.com]

Библиотеку SLRE следует применять с осторожностью в случае, если мало осталось свободной памяти RAM, потому что стек может перезаписать области памяти переменных (вызовы slre_match помещают в стек объемную служебную структуру regex_info). Для снижения требований на место под стек можно уменьшить значения констант MAX_BRANCHES и MAX_BRACKETS (по умолчанию они равны 100).

#define MAX_BRANCHES 100
#define MAX_BRACKETS 100

Если уменьшить обе эти константы до 5, то размер структуры regex_info уменьшается до 70 байт.

[Ссылки]

1. SLRE: Super Light Regular Expression library site:github.com.
2. T-Rex: облегченная библиотека regex.
3. Жадные и ленивые квантификаторы site:learn.javascript.ru.