Расширенные регулярные выражения - поиск в строках

Введение

Регулярные выражения являются очень удобным и мощным средством поиска данных в тексте. Но с точки зрения поиска информации в текстах на русском языке (да и английском, хотя там проблема морфологии не так остра) обычные регекспы помогают мало. Причина тому - очень сложное словообразование в языке. Более того, естественный язык сплошь состоит из нерегулярностей в морфологии. Искать информацию в таких условиях становится достаточно сложной задачей.

Расширенные регулярные выражения (RegexEx) - это часть поисковой машины, которая отвечает за поиск паттерна в текстовой строке. Они содержат простые средства для исключения морфологии языка из числа мешающих поиску (сравнению строк в частном случае) факторов. К примеру, приведение слов к базовым формам и сравнение базовых форм снимает значительную часть трудностей при сравнении лексем идет и шел. Заметим, что расширенные регекспы работают только с UNICODE-строками, поэтому проблемы с национальными символами исключаются автоматически. В дополнении к чисто морфологическим операциям, расширенные регулярные выражения умеют выполнять нечеткий поиск, то есть сравнивать строки с учетом опечаток в отдельных словах или пропуска целых слов. При наличии полной версии словаря с тезаурусом грамматическая машина также может прозрачно использовать синонимы и разным образом связанные слова для небуквального сопоставления паттерна и заданного текста.

По своей функциональности RegexEx'ы напоминают обычные регулярные выражения. Технически возможно даже использовать расширенные регулярные выражения как обычные, поскольку команда -regex соответствующим образом меняет алгоритм. Однако возникающий при этом overhead слишком велик, поэтому API ГМ не поддерживает использование расширенных регекспов вместо классических.

Техническая реализация RegexEx'ов базируется на функциональных возможностях поискового движка. Другими словами, расширенные регулярные выражения - это поисковый движок минус краулер и индексатор, то есть исключая средства для извлечения текстовых данных из файлов разных форматов, архивов, веб-серверов и т.д.

Краткое введение в расширенные регулярные выражения

Прежде всего необходимо отметить, что в отличие от классических выражений расширенные регэкспы работают на уровне слов, а не символов. Поэтому не требуется каких-либо специальных формальных конструкций в паттерне для того, чтобы выделять в тексте лексемы, убирая пробелы и учитывая знаки препинания. К примеру, паттерн: кошка OR собака будет успешно найден в тексте "друзья подарили ему кошку."

Рассмотрим практический пример. Допустим, поиск будет вестись в тексте:

const std::wstring TXT( L"Серые кошки сладко спят. Лучше КОШЕК и котов не будите!" );

Создаем объект регэкспа:

HREGEXEX hRegex = sol_CreateRx( hEng, L"кошечка" );

Включаем сложную морфологию:

sol_SetMorphologyRx( hRegex, 2 )

Выполняем поиск:

if( sol_SearchRx( hRegex, TXT.begin(), TXT.end() ) )

И в случае успеха напечатаем контексты - фрагменты текста, с которыми успешно соотнесен исходный паттерн:

for( int i=0; i<sol_CountMatchesRx(hRegex); i++ )
 {
  sol_GetMatchTextRx( hRegex, i, wbuffer, sizeof(wbuffer)/2-1 );
  // содержимое wbuffer'а печатаем на консоли...
  ...
 }

В нашем случае мы увидим 2 успешных контекста: слова кошки и КОШЕК.

Сейчас Вы увидите, насколько просто включить более сложные проверки с использованием тезауруса. Активируем тезаурус для нашего регэкспа:

sol_EnableThesaurusRx( hEng, hRegex, 1, true, true, true, true );

В данном случае мы разрешаем учитывать любые связи между словами, хотя достаточно будет включить только грамматически связи. Выполнив поиск и печать результатов (код уже приведен выше), мы увидим три успешных контекста: кошки, КОШЕК и котов. Последнее слово - котов - появилось в результатах из-за своей семантической связи с искомым словом кошка (см. подробнее о тезаурусе). Если в тексте встретится слово кошачий, то оно также даст успех сопоставления с паттерном за счет грамматической связи (существительное-прилагательное).

В конце необходимо удалить объект:

sol_DeleteRx( hRegex );

Синтаксис паттернов для расширенных регулярных выражений практически полностью описан в разделе "паттерны запросов" поискового движка. В частности, логические выражения могут свободно применяться в расширенных регэкспах.

Объявление процедур API

Как и остальные процедуры API грамматической машины, нижеописанные функции объявлены в заголовочном файле sdk\include\solarix_grammar_engine.h, который входит в состав SDK грамматического движка.

Загрузка необходимых модулей

В отличие от классических регулярных выражений, расширенные регэкспы требуют предварительной загрузки модулей для выполнения грамматического анализа - см. sol_LoadGrammarEngine.

Создание паттерна

Создание регекспа

HREGEXEX sol_CreateRx( HGREN hEngine, const wchar_t* Pattern )

Аргументы:

hEngine - дескриптор созданного объекта движка - см. sol_CreateGrammarEngine и sol_CreateSearchEngine.

Pattern - текстовое представление регекспа

Возвращается: указатель на объект с инициализированным по умолчанию регулярным выражением. Для изменения разнообразных параметров используются соответствующие процедуры.

Прикладная программа должна удалить объект после его использования.

void sol_DeleteRx( HREGEXEX hRegex )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Установка параметров

По умолчанию в созданном регэкспе отключена морфология, нечеткий поиск, тезаурус и другие расширенные возможности. Для установки отдельных параметров используются нижеперечисленные процедуры.

Установка режима морфологии

void sol_SetMorphologyRx( HREGEXEX hRegex, int Mode )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Mode - флаг устанавливаемого режима, может принимать значения: 0 - морфология отключена, 1 - базовая (словарная) морфология, см. команду -wordforms, 2 - расширенная морфология, см. команду -dynforms, 3 - стемминг, см. команду -stems.
 

Установка режима проверки синтаксиса

void sol_SetSyntaxRx( HREGEXEX hRegex, int Mode )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Mode - флаг устанавливаемого режима, может принимать значения: 0 - синтаксис не анализируется, 1 - упрощенная проверка согласования слов, 2 - полный синтаксический анализ. Упрощенная проверка синтаксиса действует аналогично команде -correlate поисковой системы, то есть проверяет грамматическое согласование слов в находимых контекстах. В случае нарушения согласованности слов достоверность результата понижается, что позволяет при сортировке результатов давать больший приоритет грамматически обоснованным результатам. Полный синтаксический анализ работает аналогично команде -aa поискового движка. Для правильного функционирования необходимо, чтобы в загруженном словаре был модуль синтаксического анализа.
 

Все слова в контекста должны быть в пределах одного предложения

void sol_SetSameSentenceRx( HREGEXEX hRegex )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Процедура действует аналогично команде -distance=s поисковой системы, то есть слова находимого контекста не должны разделяться знаками препинания типа точки. Обычно этот режим наиболее осмыслен, если, конечно, анализируемый текст разбит на предложения.

 

Установка максимального расстояния между словами в контексте

void sol_SetDistanceRx( HREGEXEX hRegex, int Distance )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Distance - максимальное расстояние в словах, 1 означает непосредственную близость.

Процедура действует аналогично команде -distance=n поисковой системы. Слова находимого контекста должны быть друг от друга не далее заданного числа лексем. Установка максимального расстояния позволяет исключить из результатов бессмысленные контексты, когда слова паттерна находятся в разных частях текста и никак не связаны. Следует внимательно относится к выбору данного параметра при использовании логических выражений в паттерне.

 

Порядок слов в найденном контексте должен соответствовать исходному паттерну

void sol_SetOrderedRx( HREGEXEX hRegex, int Ordered )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Ordered - флаг учета порядка слов.

Команда -ordered поисковой системы оказывает тот же эффект. В некоторых языках с фиксированным порядком слов или для поиска словосочетаний со сложившимся порядком слов задание такого ограничения позволяет уменьшить поисковый шум.

 

Включение нечеткого поиска, при котором допускается сопоставление слов с опечатками

void sol_SetSoundexRx( HREGEXEX hRegex, int Enable )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Enable - флаг включения нечеткого сравнения.

Процедура работает аналогично команде -soundex поискового движка.

 

Можно ли пропустить часть слов исходного паттерна

void sol_AllowPartialMatchingRx( HREGEXEX hRegex, int Allow )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Enable - флаг включения режима неполного сопоставления искомого паттерна и фрагмента текста.

Процедура работает аналогично команде -allow_partial=xxx поискового движка. Данная возможность дополняет возможности нечеткого поиска, включаемые процедурой sol_SetSoundexRx.

 

При сопоставлении слов отбрасывать диакритические значки, что удобно для многих европейских языков:

void sol_SetStripAccentsRx( HREGEXEX hRegex, int Strip )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

Strip - флаг включения режима исключения значков.

Аналогом процедуры в поисковом движке является команда -strip_accents.

 

По умолчанию регулярное выражение дает множество сопоставлений. Если интерес представляет только первый контекст, к примеру нужно убедиться в возможности сопоставления как таковой, то можно воспользоваться процедурой;

void sol_SetOnlyOneMatchRx( HREGEXEX hRegex, int OnlyOne )

Аргументы:

hRegex - возвращенный sol_CreateRx дескриптор.

OnlyOne - флаг включения режима поиска только одного сопоставления паттерна и фрагмента текста.

В поисковом движке аналогичную функцию несет команда -onceperfile.

 

Чтобы включить тезаурус для сопоставления связанных слов, используется процедура:

void sol_EnableThesaurusRx( HGREN hEngine, HREGEXEX hRegex, int Jumps, int Synonyms, int Grammar, int Semantics, int Translations )

В поисковом движке есть две команды: -semnet и -links, которые включают тезаурус и настраивают его.

Поиск по строке

int sol_SearchRx( HREGEXEX hRegex, const wchar_t* Begin, const wchar_t* End )

Аргументы Begin и End - это итераторы, указывающие на участок текста, в котором ведется поиск.

Результат работы будет 1, если найден хоть один контекст, иначе 0.

Результаты поиска

Кроме самого факта успешной фиксации контекста интересно бывает узнать, какие участки текста попали под паттерн. Один паттерн может быть зафиксирован на нескольких участках текста (например, на нескольких лексемах). Процедура

int sol_CountMatchesRx( HREGEXEX hRegex )

возвращает количество фрагментов текста (контекстов фиксации). Для получения самого контекста используется процедура:

int sol_GetMatchTextRx( HREGEXEX hRegex, int Index, wchar_t* Buffer, int BufferSize )

Текст будет помещен в участке памяти, на начало которого указывает аргумент Buffer, причем результат в любом случае будет не длиннее BufferSize байтов.

В некоторых случаях контекст фиксации бывает найден с достоверностью менее 100%. К примеру, при включении нечеткого поиска sol_SetSoundexRx или при разрешении пропускать слова паттерна sol_AllowPartialMatchingRx. Чтобы получить оценку достоверности контекста, используется процедура:

float sol_GetMatchRankRx( HREGEXEX hRegex, int Index )

 

Примеры работы с расширенными регулярными выражениями

  © Mental Computing 2010
изменено 16-Aug-11