Собственные функции библиотеки 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
Поддерживаются следующие опции:
Третьим параметром (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) задаются опции сравнения. Опции могут быть с ледующие:
Седьмым параметром (int *ovector) указывается массив, который будет содержать пары номеров символов, которые определяют результаты поиска. Первая пара (ovector[0] и ovector[1]) определяет подстроку, совпадающую со всем шаблоном. Первый элемент пары (ovector[0]) содержит номер первого символа, а второй (ovector[1]) - номер последнего символа. Последующие пары определяют построки, совпадающие с группами шаблонов, содержащихся в скобках. Восьмой параметр (int ovecsize) задает максимальный размер массива ovector. В случае успеха функция pcre_exec возвращает количество заполненных пар в массиве ovector. В противном случае - одно из следующих отрицательных значений:
#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_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 в командной строке.:)
(c)Ерижоков А.А., 2001.
Использование данного документа разрешено только с согласия автора и с указанием первоисточника:
DH's Linux Site