Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабы СПО / РегЭкспы методичка.docx
Скачиваний:
54
Добавлен:
12.04.2015
Размер:
254.09 Кб
Скачать

3.5. Чего не умеют регулярные выражения

Проверять сбалансированность симметричных конструкций (begin–end, открывающих/закрывающих скобок и т.п.). Например, для случая

beginbeginbeginendendend

проблематично составить регулярное выражение, которое заберет текст от второго «begin» до предпоследнего «end». Регулярные выражения в принципе не приспособлены для этого. Возможные пути решения см. в [1], стр.217-218, и [4].

4. Использование библиотеки RegExpr

Библиотека RegExpr написана на Delphi, но ее можно подключать к программам на C++ Builder 6.0. Работа с регулярными выражениями реализована в классе TRegExpr. Далее описываются свойства и методы этого класса, но не все, а самые необходимые для лабораторной работы. За остальными обращайтесь в HELP-файл или дистрибутив библиотеки. Все примеры даются на С++ (аналоги на Delphi нетрудно посмотреть в документации).

Класс TRegExpr работает со строками формата AnsiString: каждый символ занимает 1 байт, сама строка хранится в динамической памяти, и ограничена размером 2 Гб. Символы нумеруются начиная с 1.

Для подключения библиотеки RegExpr в С++ Builder нужно: а) из дистрибутива библиотеки RegExpr в папку с вашим проектом скопировать файлы regexpr.pas, regexpr.hpp; б) включить в проект файл regexpr.pas, используя команду Project/Add to project; в) в заголовок программы включить строку:

#include "regexpr.hpp"

Объект класса TRegExpr создается конструктором new, например так:

TRegExpr *MyRegExpr = new TRegExpr;

4.1. Как делается поиск подстрок

Регулярное выражение присваивается свойству

__property AnsiString Expression =

{read=GetExpression, write=SetExpression};

Для поиска подстрок, соответствующих регулярному выражению, используются методы:

bool __fastcall Exec(const AnsiString AInputString);

bool __fastcall ExecPos(int AOffset = 1);

bool __fastcall ExecNext(void);

Для первого поиска вызывается метод Exec, ему передается строка с текстом, в котором следует искать образец. Если поиск был успешным, метод вернет true, если нет – false. Для последующих поисков используется метод ExecNext (он продолжает поиск с позиции, на которой завершился прошлый поиск) и метод ExecPos (ищет с указанной позиции). Оба метода возвращают true, если нашли подстроку, и false при неудаче.

Все эти методы после каждого поиска помещают характеристики найденной подстроки в свойства класса TRegExpr:

  • __property AnsiString Match[int Idx] = {read=GetMatch};

В элементе Match[0] хранится подстрока, соответствующая регулярному выражению целиком. В элементах Match], i=1,2,3,… возвращаются подстроки, соответствующие 1й, 2й и т.д. группе (что такое «группа» см. п.3.3.5 и примеры на стр.13). Если регулярное выражение или группа не найдены, соответствующий элемент Match]=”” (пустой строке).

  • __property int MatchLen[int Idx] = {read=GetMatchLen};

Массив содержит длины найденных подстрок. В элементе MatchLen[0] содержится длина подстроки, отвечающей регулярному выражению целиком. В элементах MatchLen], соответственно, длины подстрок 1й, 2й и т.д. групп. Если регулярное выражение или группа отсутствуют, соответствующий MatchLen] = –1.

  • __property int MatchPos[int Idx] = {read=GetMatchPos};

Массив содержит позицию (смещение) подстроки и ее групп относительно начала входной строки. Позиции отсчитываются от 1. Аналогично предыдущему свойству, MatchPos[0] хранит позицию подстроки, соответствующей всему регулярному выражению, MatchPosi ] – позицию i й группы и т.д. Если регулярное выражение или группа не найдены, соответствующий MatchPosi ]=–1.

  • __property int SubExprMatchCount =

{read=GetSubExprMatchCount, nodefault};

Свойство содержит количество групп (подвыражений), найденных при последнем поиске. Если выражение не найдено (Exec… вернул false), или выражение не содержит групп нет, то SubExprMatchCount = 0.

Имейте в виду, что некоторые группы могут быть не найдены. Например, шаблон ‘(\d*)(\d)’ для поиска чисел содержит две группы: правая (2я) группа отделяет младшую цифру, левая (1я) группа захватывает все старшие цифры. Так, в тексте “Васе шел 104-й год” будет найдено Match[0]=”104”, Match[1]=”10”, Match[2]=”4”. А при поиске в тексте “Жене шел 3-й год” будет найдено Match[0]=”3”, Match[1]=”” (пустая группа: старших цифр нет), Match[2]=”3”.

Пример: Ниже приведен листинг консольного приложения на C++Builder, которое ищет в текстовом файле строки, удовлетворяющие регулярному выражению.

В строках С++ символ «\» применяется в ESC-последовательностях, поэтому при записи шаблонов регулярных выражений символ «\» заменяется на «\\».

#pragma hdrstop

#include <iostream.h> // ввод-вывод на консоль

#include <stdio.h> // работа с файлами

#include <conio.h> // для вызова getch()

#include "regexpr.hpp" // регулярные выражения

#pragma argsused

int main(int argc, char* argv[])

{

char file_name[] = "TEST.TXT";

FILE *file;

if (( file = fopen( file_name, "r")) != NULL ) {

// определяем размер файла

fseek( file, 0, SEEK_END );

size_t file_size = ftell( file );

fseek( file, 0, SEEK_SET );

// резервируем буфер

AnsiString buf;

buf.SetLength( file_size ); // длина буф.= размеру файла

// считываем файл в буфер целиком

if ( fread( buf.c_str(), 1, file_size , file )) {

TRegExpr *MyRegExpr = new TRegExpr; // создаем РегЭсп

MyRegExpr->Expression = "\\d+"; // задаем шаблон '\d+'

// поиск регулярными выражениями

if ( MyRegExpr->Exec(buf)){ //если 1-й поиск удачный..

do { // ...продолжаем поиск, пока не найдем всё

// с найденной строкой что-то делаем,

// например, выводим на экран

cout << MyRegExpr->Match[0] << endl;

} while ( MyRegExpr->ExecNext());

}

delete MyRegExpr; // удаляем объект РегЭксп

}

fclose( file ); // закрываем файл, он больше не нужен

}

getch();

return 0;

}

Специально для задач распознавания, соответствует ли строка регулярному выражению, в модуле RegExpr есть глобальная функция (это не метод класса TRegExpr !!!):

bool __fastcall ExecRegExpr(

const AnsiString ARegExpr, // шаблон регулярного выражения

const AnsiString AInputStr); // текст для проверки

Функция возвращает true, если строка AInputStr (вся целиком) покрывается регулярным выражением ARegExpr, иначе – false. Если регулярное выражение содержит ошибки, функция вызывает исключение, поэтому ее рекомендуется вызывать внутри trycatch.

В п.3.3.7 описывались модификаторы, управляющие работой регулярных выражений. Класс TRegExpr позволяет задать глобальное влияние модификаторов на всё регулярное выражение в целом. Ниже перечислены свойства класса TRgExpr, управляющие работой глобальных модификаторов, и их значения по умолчанию (расшифровка действия каждого модификатора дана в таблице 5):

__property bool ModifierI // (?i) = false

__property bool ModifierR // (?r) = true

__property bool ModifierM // (?m) = false

__property bool ModifierS // (?s) = true

__property bool ModifierG // (?g) = true

__property bool ModifierX // (?x) = false

Соседние файлы в папке Лабы СПО