Собственные функции
Собственные функции библиотеки PCRE более
развитые, имеют больше возможностей, а также поддерживают, в отличие от
POSIX-совместимых, национальные кодировки, в том числе Unicode.
Описания функций содержатся в заголовочном файле /usr/include/pcre.h и в
библиотеке /usr/lib/pcre.a. Вот список функций с параметрами:
pcre *pcre_compile(const char *pattern, int options, const char **errptr,
int *erroffset, const unsigned char *tableptr);
pcre_extra *pcre_study(const pcre *code, int options, const char **errptr);
int pcre_exec(const pcre *code, const pcre_extra *extra, const char *subject,
int length, int startoffset, int options, int *ovector, int ovecsize);
int pcre_copy_substring(const char *subject, int *ovector, int stringcount,
int stringnumber, char *buffer, int buffersize);
int pcre_get_substring(const char *subject, int *ovector, int stringcount,
int stringnumber, const char **stringptr);
int pcre_get_substring_list(const char *subject, int *ovector,
int stringcount, const char ***listptr);
void pcre_free_substring(const char *stringptr);
void pcre_free_substring_list(const char **stringptr);
const unsigned char *pcre_maketables(void);
int pcre_fullinfo(const pcre *code, const pcre_extra *extra, int what,
void *where);
int pcre_info(const pcre *code, int *optptr, int *firstcharptr);
char *pcre_version(void);
void *(*pcre_malloc)(size_t);
void (*pcre_free)(void *);
Функция pcre_compile служит для преобразования
регулярного выражения во внутренний формат. Первым параметром (const char
*pattern) передается строка с регулярным выражением. Второй
параметр (int options) задает опции преобразования. Можно
использовать несколько опций одновременно, применив к ним операцию
побитового "или" (|).
PCRE_CASELESS|PCRE_DOTALL|PCRE_MULTILINE
Поддерживаются следующие опции:
- PCRE_ANCHORED
Данная опция указывает, что сравнение будет
производится только с началом строки, даже если поиск производится в
многострочной переменной.
- PCRE_CASELESS
Поиск без учета регистра. Аналог опции /i
в Perl.
- PCRE_DOLLAR_ENDONLY
Указывает, что символ доллара ($)
означает конец строки всей строки, а не символ перед переносом строки
(\n). Т.е. если опция не установлена, то шаблон типа .$
будет обозначать любой символ перед символом новой строки в
многострочной переменной, а не настоящий конец строки.
- PCRE_DOTALL
При установленной опции, шаблон .
означает любой символ, в том числе и символ новой строки (\n). В
противном случае символ новой строки неучитывается. Также любой шаблон
отрицания, например [^a], будет учитывать и символ новой строки.
- PCRE_MULTILINE
По умолчанию, функции PCRE рассматривают
переменную, в которой производится поиск, как однострочную, т.е. не
содержащую символы \n. Эта опция позволяет обрабатывать
многострочные переменные. В этом случае, символ-шаблон ^
указывает не только на самое начало строки, но и на символы после
каждого переноса строки, а шаблон $ указывает не только на самый
конец строки, но и на символы перед каждым переносом стороки.
- PCRE_UNGREEDY
Устанавливает режим поиска, когда действие всех
шаблонов ограничивается минимальным совпадением, т.е. как будто после
каждого символа-шаблона стоит модификатор ?.
- PCRE_UTF8
Включает поддержку UTF-8.
Третьим параметром (const char **errptr) указывается строка, в которую будет
выводится сообщение об ошибке в случае наличия таковой в шаблоне. В
переменную, переданную четвертым параметром (int *erroffset),
заносится номер символа в строке шаблона, на котором произошла ошибка.
Пятый параметр (const unsigned char *tableptr) служит для
поддержки национальных символов. О нем попозже.
В случае успеха функция возвращает указатель на
переменную, содержащую преобразованный шаблон. Переменная типа
pcre, которая в дальнейшем будет использоваться для поиска. В
противном случае возвращает NULL.
#include <stdio.h>
#include <pcre.h>
int main(int argc, char* argv[])
{
pcre *f; /* переменная для хранения преобразованного шаблона */
char *pattern="(\\d{2})[-/\\.](\\d{2})[-/\\.](\\d{2})?(\\d{2}"; /* шаблон с ошибкой */
const char *errstr; /* буфер для сообщения об ошибке */
int errchar; /* номер символа */
if((f=pcre_compile(pattern,PCRE_CASELESS|PCRE_MULTILINE,&errstr,&errchar,NULL))==NULL)
{
printf("Ошибка: %s\nСимвол N%i\nШаблон:%s\n",errstr,errchar,pattern);
exit(1);
}
printf("Все прошло нормально!\n");
return 0;
}
Собирается программа таким образом:
gcc -o имя_файла имя_файла.c `pcre-config --libs`
Например, если файл исходника называется
example10.c, то собираться он будет при помощи команды:
gcc -o example10 example10.c `pcre-config --libs`
Вывод:
Ошибка: missing )
Символ N40
Шаблон:(\d{2})[-/\.](\d{2})[-/\.](\d{2})?(\d{2}
Функция pcre_exec производит сравнение строки с
преобразованным шаблоном. Первым параметром (const pcre *code) указывается
переменная, содержащая преобразованный шаблон. Вторым параметром (const pcre_extra
*extra) указывается значение переменной, созданное функцией
pcre_study (см. ниже). Если функция pcre_study не
вызывалась, можно указывать значение NULL. Третьим параметром
(const char *subject) передается строка, в которой будет
производится поиск. Четвертым параметром (int length) передается длина подстроки, в которой производится поиск.
Пятым параметром (int startoffset) является смещение в строке subject, с которого начинается подстрока.
Т.е. можно производить поиск не во всей строке, а только в ее части, ограничивая действие pcre_exec при помощи параметров
length и startoffset. При помощи шестого параметра (int options) задаются опции сравнения. Опции могут быть
с
ледующие:
- PCRE_ANCHORED
То же, что и у pcre_compile.
- PCRE_NOTBOL
PCRE_NOTEOL
- PCRE_NOTEMPTY
Указывает, что пустая строка не может
совпадать с шаблоном. Это относится к таким шаблона, как a?b?.
Седьмым параметром (int *ovector) указывается
массив, который будет содержать пары номеров символов, которые
определяют результаты поиска. Первая пара (ovector[0] и
ovector[1]) определяет подстроку, совпадающую со всем шаблоном.
Первый элемент пары (ovector[0]) содержит номер первого символа,
а второй (ovector[1]) - номер последнего символа. Последующие
пары определяют построки, совпадающие с группами шаблонов, содержащихся
в скобках. Восьмой параметр (int ovecsize) задает максимальный
размер массива ovector. В случае успеха функция pcre_exec
возвращает количество заполненных пар в массиве ovector. В
противном случае - одно из следующих отрицательных значений:
- PCRE_ERROR_NOMATCH (-1)
Не найдено совпадений с шаблоном.
- PCRE_ERROR_NULL (-2)
Один из указателей - code,
subject, ovector - имеет значение NULL или
ovecsize равно 0.
- PCRE_ERROR_BADOPTION (-3)
Указана неизвестная опция.
- PCRE_ERROR_BADMAGIC (-4)
PCRE хранит четырех байтовое число в начале
преобразованного шаблона для собственных нужд. Данная ошибка указывает,
что число некорректное.
- PCRE_ERROR_UNKNOWN_NODE (-5)
Неизвестный элемент шаблона.
- PCRE_ERROR_NOMEMORY (-6)
Не хватает памяти.
#include <stdio.h>
#include <pcre.h>
int main(int argc, char* argv[])
{
pcre *f; /* переменная для хранения преобразованного шаблона */
char *pattern="([0-2][1-9]|[3][0-1])[-/\\.]([0][1-9]|[1][0-2])[-/\\.](\\d{2})?(\\d{2})"; /* шаблон */
const char *errstr; /* буфер для сообщения об ошибке */
int errchar; /* номер символа */
char *str1="32/08/2001"; /* первая строка для примера */
char *str2="Сегодня - 22.07.01"; /* вторая строка для примера */
int vector[50]; /* массив для результатов */
int vecsize=50; /* размер массива */
int pairs; /* количество найденных пар */
int i,j;
printf("Шаблон - \"%s\"\n",pattern);
if((f=pcre_compile(pattern,PCRE_CASELESS|PCRE_MULTILINE,&errstr,&errchar,NULL))==NULL)
{
printf("Ошибка: %s\nСимвол N%i\nШаблон:%s\n",errstr,errchar,pattern);
}
else
{
printf("---\nСтрока - \"%s\"\n",str1);
if((pairs=pcre_exec(f,NULL,str1,strlen(str1),0,PCRE_NOTEMPTY,vector,vecsize))<0)
{
printf("Ошибка! Номер: %i\n",pairs);
}
else
{
printf("Найдено совпадение! %i подстрок:\n",pairs);
for(i=0;i<pairs;i++)
{
printf("%i-я подстрока - ",i);
for(j=vector[i*2];j<vector[i*2+1];j++)
putchar(str1[j]);
putchar('\n');
}
}
printf("---\nСтрока - \"%s\"\n",str2);
if((pairs=pcre_exec(f,NULL,str2,strlen(str2),0,PCRE_NOTEMPTY,vector,vecsize))<0)
{
printf("Ошибка! Номер: %i\n",pairs);
}
else
{
printf("Найдено совпадение! %i подстрок:\n",pairs);
for(i=0;i<pairs;i++)
{
printf("%i-я подстрока - ",i);
for(j=vector[i*2];j<vector[i*2+1];j++)
putchar(str2[j]);
putchar('\n');
}
}
}
return 0;
}
Вывод:
Шаблон - "([0-2][1-9]|[3][0-1])[-/\.]([0][1-9]|[1][0-2])[-/\.](\d{2})?(\d{2})"
---
Строка - "32/08/2001"
Ошибка! Номер: -1
---
Строка - "Сегодня - 22.07.01"
Найдено совпадение! 5 подстрок:
0-я подстрока - 22.07.01
1-я подстрока - 22
2-я подстрока - 07
3-я подстрока -
4-я подстрока - 01
При нескольких операциях сравнения при использовании
одного и того же шаблона желательно (но не обязательно:)) использовать
функцию pcre_study. Функция ускоряет
работу программы, создавая переменную, которая хранит дополнительные
сведения о шаблоне, ускоряющие его обработку функцией pcre_exec.
Первым параметром (const pcre *code) передается переменная,
созданная функцией pcre_comp. Вторым параметром (int
options) указываются опции обработки шаблона. На момент написания
статьи их нет.:) Так что можно (и нужно) указывать 0 вторым
параметром. Третьим параметром (const char **errptr) должен быть
указатель на строку, в которую будет записано сообщение об ошибке, если
таковая возникнет в процессе работы. /* Честно говоря, я не нашел
необходимости использовать эту функцию. Но это мое личное мнение.:) */
#include <stdio.h>
#include <pcre.h>
int main(int argc, char* argv[])
{
pcre *f; /* переменная для хранения преобразованного шаблона */
pcre_extra *f_ext; /* переменная для хранения дополнительных данных */
char *pattern="([0-2][1-9]|[3][0-1])[-/\\.]([0][1-9]|[1][0-2])[-/\\.](\\d{2})?(\\d{2})"; /* шаблон */
const char *errstr; /* буфер для сообщения об ошибке */
int errchar; /* номер символа */
char *str1="30/13/01"; /* первая строка для примера */
char *str2="Сегодня - 12.08.1999"; /* вторая строка для примера */
int vector[50]; /* массив для результатов */
int vecsize=50; /* размер массива */
int pairs; /* количество найденных пар */
int i,j;
printf("Шаблон - \"%s\"\n",pattern);
if((f=pcre_compile(pattern,PCRE_CASELESS|PCRE_MULTILINE,&errstr,&errchar,NULL))==NULL)
{
printf("Ошибка: %s\nСимвол N%i\nШаблон:%s\n",errstr,errchar,pattern);
}
else
{
f_ext=pcre_study(f,0,&errstr);
printf("---\nСтрока - \"%s\"\n",str1);
if((pairs=pcre_exec(f,f_ext,str1,strlen(str1),0,PCRE_NOTEMPTY,vector,vecsize))<0)
{
printf("Ошибка! Номер: %i\n",pairs);
}
else
{
printf("Найдено совпадение! %i подстрок:\n",pairs);
for(i=0;i<pairs;i++)
{
printf("%i-я подстрока - ",i);
for(j=vector[i*2];j<vector[i*2+1];j++)
putchar(str1[j]);
putchar('\n');
}
}
printf("---\nСтрока - \"%s\"\n",str2);
if((pairs=pcre_exec(f,f_ext,str2,strlen(str2),0,PCRE_NOTEMPTY,vector,vecsize))<0)
{
printf("Ошибка! Номер: %i\n",pairs);
}
else
{
printf("Найдено совпадение! %i подстрок:\n",pairs);
for(i=0;i<pairs;i++)
{
printf("%i-я подстрока - ",i);
for(j=vector[i*2];j<vector[i*2+1];j++)
putchar(str2[j]);
putchar('\n');
}
}
}
return 0;
}
Соответсвенно, вывод:
Шаблон - "([0-2][1-9]|[3][0-1])[-/\.]([0][1-9]|[1][0-2])[-/\.](\d{2})?(\d{2})"
---
Строка - "30/13/01"
Ошибка! Номер: -1
---
Строка - "Сегодня - 12.08.1999"
Найдено совпадение! 5 подстрок:
0-я подстрока - 12.08.1999
1-я подстрока - 12
2-я подстрока - 08
3-я подстрока - 19
4-я подстрока - 99
Циклы типа for(..), которые использовались для вывода
найденных строк, являются лишними, т.к. в библиотеке PCRE есть функции,
выполняющие сохранение найденных подстрок в строковые переменные. Это
функции pcre_copy_substring, pcre_get_substring и
pcre_get_substring_list.
Функции
pcre_copy_substring и pcre_get_substring> вытаскивают из
строки одну из найденных подстрок. Для этого указывается номер
найденной подстроки. Отличаются эти функции друг от друга тем, что
pcre_copy_substring записывает результат в буфер, которому уже
выделена память, а pcre_get_substring выделяет память для
буфера и записывает в него результат. Первые четыре параметра у
указанных функций одинаковые: первым параметром (const char
*subject) указывается строка, в которой производился поиск, вторым
параметром (int *ovector) указывается массив, созданный функцией
pcre_exec и содержащий значения, определяющие номера первых и
последних символов найденных подстрок, третьим параметром (int
stringcount) указывается значение, возвращенное функцией
pcre_exec, т.е. количество найденных пар типа первый и последний
символ, четвертым параметром (int stringnumber) указывается
номер нужной подстроки.
Пятым параметром (char *buffer) функции pcre_copy_substring
указывается буфер, в который будет записан результат. Шестым (int
buffersize) - указывается размер буфера.
В функции pcre_get_substring пятым параметром
(const char **stringptr) передается указатель на буфер, в
который и будет записан результат.
В случае успеха функции возвращают длину подстроки, в
противном случае - отрицательное значение, одно из нижеперечисленных:
- PCRE_ERROR_NOMEMORY (-6)
Нехватка памяти. Возникает при указании пятым
параметром в функции pcre_copy_substring буфера недостаточной
длины, или при ошибке распределения памяти в функции
pcre_get_substring
- PCRE_ERROR_NOSUBSTRING (-7)
Подстрока не найдена.
Для того, чтоб вытащить все найденные подстроки из
строки, используется функция pcre_get_substring. Первые три
параметра у нее те же, что и у функций pcre_copy_substring и
pcre_get_substring. Четвертым параметром (const char
***listptr) передается указатель на указатели на строки, т.е.
указатель на массив строк, в который и будет записан результат.
В случае успеха возвращает 0, в противном
случае - отрицательное значение PCRE_ERROR_NOSUBSTRING (-7),
означающее ту же ошибку, что и в случае с функцией
pcre_get_substring_list.
Функция
pcre_free_substring служит для освобождения памяти, выделенной
функцией pcre_get_substring, а функция
pcre_free_substring_list освобождает память, выделенную функцией
pcre_get_substring_list
#include <stdio.h>
#include <pcre.h>
int main(int argc, char* argv[])
{
pcre *f; /* переменная для хранения преобразованного шаблона */
pcre_extra *f_ext; /* переменная для хранения дополнительных данных */
char *pattern="([0-2][1-9]|[3][0-1])[-/\\.]([0][1-9]|[1][0-2])[-/\\.](\\d{2})?(\\d{2})"; /* шаблон */
const char *errstr; /* буфер для сообщения об ошибке */
int errchar; /* номер символа */
char *str="Сегодня - 01.10.2002"; /* строка для примера */
int vector[50]; /* массив для результатов */
int vecsize=50; /* размер массива */
int pairs; /* количество найденных пар */
char buff1[200]; /* буфер для функции pcre_copy_substring */
const char *buff2; /* буфер для функции pcre_get_substring */
const char **buff3; /* для функции pcre_get_substring_list */
int i,j;
printf("Шаблон - \"%s\"\n",pattern);
if((f=pcre_compile(pattern,PCRE_CASELESS|PCRE_MULTILINE,&errstr,&errchar,NULL))==NULL)
{
printf("Ошибка: %s\nСимвол N%i\nШаблон:%s\n",errstr,errchar,pattern);
}
else
{
f_ext=pcre_study(f,0,&errstr);
printf("---\nСтрока - \"%s\"\n",str);
if((pairs=pcre_exec(f,f_ext,str,strlen(str),0,PCRE_NOTEMPTY,vector,vecsize))<0)
{
printf("Ошибка! Номер: %i\n",pairs);
}
else
{
printf("Найдено совпадение! %i подстрок:\n",pairs);
if(pcre_copy_substring(str,vector,pairs,0,buff1,199)<0)
printf("Ошибка pcre_copy_substring!\n");
else
printf("pcre_copy_substring:\n0-я подстрока: %s\n",buff1);
if(pcre_get_substring(str,vector,pairs,3,&buff2)<0)
printf("Ошибка pcre_get_substring!\n");
else
{
printf("pcre_get_substring:\n3-я подстрока: %s\n",buff2);
pcre_free_substring(buff2);
}
if(pcre_get_substring_list(str,vector,pairs,&buff3)<0)
printf("Ошибка pcre_get_substring_list!");
else
{
printf("pcre_get_substring_list:\n");
for(i=0;i<pairs;i++)
printf("%i-я подстрока: %s\n",i,buff3[i]);
pcre_free_substring_list(buff3);
}
}
}
return 0;
}
Результат:
Шаблон - "([0-2][1-9]|[3][0-1])[-/\.]([0][1-9]|[1][0-2])[-/\.](\d{2})?(\d{2})"
---
Строка - "Сегодня - 01.10.2002"
Найдено совпадение! 5 подстрок:
pcre_copy_substring:
0-я подстрока: 01.10.2002
pcre_get_substring:
3-я подстрока: 20
pcre_get_substring_list:
0-я подстрока: 01.10.2002
1-я подстрока: 01
2-я подстрока: 10
3-я подстрока: 20
4-я подстрока: 02
Рассмотрим простейший пример для разбиения предложения по
словам. Выделить одно слово из предложения не составляет труда.
Достаточно использовать шаблон \w*, вызвать функцию
pcre_compile, затем pcre_study, затем pcre_exec, и
в конце получить подстроку при помощи функции
pcre_get_substring. Но нам нужны все слова. Для этого
необходимо организовать цикл, который при каждом проходе будет находить
одно слово, и будет продолжаться до тех пор, пока предложение не
закончится. При каждом проходе будут вызываться функции
pcre_exec и pcre_get_substring. При этом необходимо
учесть, чтоб поиск в предложении при каждом проходе цикла начинался с
символа, являющимся последним в найденной при предыдущем проходе
подстроке. Т.е. должен изменятся пятый параметр (int startoffset)
функции pcre_exec. Вот и программа:
#include <stdio.h>
#include <pcre.h>
int main(int argc, char* argv[])
{
pcre *f; /* переменная для хранения преобразованного шаблона */
pcre_extra *f_ext; /* переменная для хранения дополнительных данных */
char *pattern="\\w*"; /* шаблон */
const char *errstr; /* буфер для сообщения об ошибке */
int errchar; /* номер символа */
char *str="Первый параметр (regex_t *preg) - это переменная, в которую заносится преобразованный шаблон, который затем используется в функции regexec.";
/* строка для примера */
int vector[50]; /* массив для результатов */
int vecsize=50; /* размер массива */
int pairs; /* количество найденных пар */
const char *buff2; /* для функции pcre_get_substring */
int i,j;
printf("Шаблон - \"%s\"\n",pattern);
if((f=pcre_compile(pattern,PCRE_CASELESS|PCRE_MULTILINE,&errstr,&errchar,NULL))==NULL)
{
printf("Ошибка: %s\nСимвол N%i\nШаблон:%s\n",errstr,errchar,pattern);
}
else
{
f_ext=pcre_study(f,0,&errstr);
printf("---\nСтрока - \"%s\"\nСлова:\n",str);
j=0;
while((pairs=pcre_exec(f,f_ext,str,strlen(str),j,PCRE_NOTEMPTY,vector,vecsize))>=0)
{
pcre_get_substring(str,vector,pairs,0,&buff2);
printf("%s\n",buff2);
pcre_free_substring(buff2);
j=vector[1]+1;
}
}
return 0;
}
А вот и вывод:
Шаблон - "\w*"
---
Строка - "Первый параметр (regex_t *preg) - это переменная, в которую заносится преобразованный шаблон, который затем используется в функции regexec."
Слова:
regex_t
preg
regexec
Как можно заметить, выведены были только слова,
состоящие из символов латинского алфавита. По умолчанию, библиотека PCRE работает
только с латиницей. Для использования символов национального алфавита
необходимо вызвать функцию pcre_maketables, которая создает
таблицу символов для использования ее функцией pcre_compile в
качестве пятого параметра (const unsigned char *tableptr).
Делается это так:
setlocale(LC_ALL,"ru_RU.KOI8-R");
tables=pcre_maketables();
pcre_compile(...,tables);
В вот и изменная программа:
#include <locale.h>
#include <stdio.h>
#include <pcre.h>
int main(int argc, char* argv[])
{
pcre *f; /* переменная для хранения преобразованного шаблона */
pcre_extra *f_ext; /* переменная для хранения дополнительных данных */
char *pattern="\\w*"; /* шаблон */
const char *errstr; /* буфер для сообщения об ошибке */
int errchar; /* номер символа */
char *str="Первый параметр (regex_t *preg) - это переменная, в которую заносится преобразованный шаблон, который затем используется в функции regexec.";
/* строка для примера */
int vector[50]; /* массив для результатов */
int vecsize=50; /* размер массива */
int pairs; /* количество найденных пар */
const char *buff2; /* для функции pcre_get_substring */
const unsigned char *tables; /* буфер для хранения таблицы символов */
int i,j;
setlocale(LC_ALL,"ru_RU.KOI8-R");
tables=pcre_maketables();
printf("Шаблон - \"%s\"\n",pattern);
if((f=pcre_compile(pattern,PCRE_CASELESS|PCRE_MULTILINE,&errstr,&errchar,tables))==NULL)
{
printf("Ошибка: %s\nСимвол N%i\nШаблон:%s\n",errstr,errchar,pattern);
}
else
{
f_ext=pcre_study(f,0,&errstr);
printf("---\nСтрока - \"%s\"\nСлова:\n",str);
j=0;
while((pairs=pcre_exec(f,f_ext,str,strlen(str),j,PCRE_NOTEMPTY,vector,vecsize))>=0)
{
pcre_get_substring(str,vector,pairs,0,&buff2);
printf("%s\n",buff2);
pcre_free_substring(buff2);
j=vector[1]+1;
}
}
return 0;
}
Вывод:
Шаблон - "\w*"
---
Строка - "Первый параметр (regex_t *preg) - это переменная, в которую заносится преобразованный шаблон, который затем используется в функции regexec."
Слова:
Первый
параметр
regex_t
preg
это
переменная
в
которую
заносится
преобразованный
шаблон
который
затем
используется
в
функции
regexec
Вот теперь все в порядке.:)
Оставшиеся функции библиотеки PCRE, которые я
не описал, большого интереса не представляют, но если тебе все же
захотелось почитать их описание, набери man pcre в командной
строке.:)
|