Научно-исследовательская лаборатория систем ЧПУ
Научно-исследовательская лаборатория систем ЧПУ

Поиск по сайту:
 

Расписание курсов "Программирование SINUMERIK 810D/840D/840Di"



Реализация поиска с использованием “wildcard” символов на базе регулярных выражений

Автор: Мартинов Г.М.
Лаборатория систем ЧПУ кафедры КСУ, МГТУ "СТАНКИН"
Опубликовано: 05.07.2004
Версия текста: 1.0

Скачать реализацию класса шаблона для VC++ 6.0 размер файла: 50.7 Kб

Постановка задачи

Нередки случаи, когда в пользовательском интерфейсе необходимо реализовать функциональность поиска. Хороший поиск это быстрый поиск, предоставляющий гибкость работы с шаблонами. Шаблоны не предполагают точное задание поискового слова, можно обойтись его фрагментом или смежным выражением для поиска целой группы. Это весьма удобно, если слово которые вы ищете длиннее 5-7 символов.

Шаблоны поиска бывают двух видов:

  • На базе "wildcard" символов;
  • На базе регулярных выражений (regular expression).

В таких продуктах как Microsoft Word или Microsoft VisualStudio можно искать используя оба варианта, хотя поиск с помощю "wildcard" символов более привычен и интуитивно понятен. Лично мне, знакомому с регулярными выражениями не первый год и проводившему не менее 50 часов в неделю с VisualStudio, приходилось использовать в поиске регулярные выражения всего не более 2-3 раз.

Поиск с использованием "wildcard" символов предполагает использовать симавол "?" для замены любого одиночного символа и символ "*" для замены любой группы символов. Наверняка "wildcard" вам приходилось использовать при работе с файловой системой DOS или Windows.

Правила конвертации

Для трансляции шаблона с набором "wildcard" символов в шаблон с регулярными выражениями были сформированы следующие 4 правила:

  1. Заменить "wildcard" символ "?" на выражение "[^n]";
  2. Заменить "wildcard" символ "*" на выражение "[^n]*";
  3. Добавить "^" в начале регулярного выражения;
  4. Добавить "$" в конец регулярного выражения.
ПРЕДУПРЕЖДЕНИЕ

Пример:

Согласно правилам шаблон поиска с "wildcard" символами "Пра?ил*" конвертируется в регулярном выражение "^Пра[^n]ил[^n]*$".

Реализация на C++

Реализация алгоритма ориентирована на работу с UNICODE и использует шаблон CAtlRegExp (см. [1]) для Visual С++ 6.0.

Не следует забывать, что некоторые символы применяемые в регулярных выражениях являются служебными и их нужно экранировать посредством символа "" (см. [2]), этим и занимается функция utility_ShadeMetacharacters().

ПРЕДУПРЕЖДЕНИЕ

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

Функция замены "wildcard" символов

Листинг функции
/* 
Replace Wildcards with Regular Expresion
Rules:
1). Replace: "?" ---> "[^n]"
2). Replace: "*" ---> "[^n]*"
3). Add: "^" to begin
4). Add: "$" to end

Example:
"J?g*" ---> "^J[^n]g[^n]*$";
*/

static _bstr_t utility_ReplaceWildcards(_bstr_t bstrString)
{
bstrString = utility_ShadeMetacharacters(bstrString, L"{[\\|+{}[\]()^$.]}");//[*?]

_bstr_t bstrRegExpresion = L"{[*?]}";

CAtlRegExp<> re;
REParseError status = re.Parse(bstrRegExpresion);
if(status != REPARSE_ERROR_OK)
return L"";

const wchar_t* pEnd = bstrString;
_bstr_t bstrRes = L"";

do
{
CAtlREMatchContext<> mc;
const wchar_t *szBegin = pEnd;
if ( !re.Match(pEnd, &mc, &pEnd) )
{
bstrRes += szBegin;
break;
}

if ( mc.m_uNumGroups > 0 )
{
const wchar_t* szStart, * szEnd;
mc.GetMatch(0, &szStart, &szEnd);
if ( szEnd == szStart )
{
bstrString = pEnd;
continue;
}

wchar_t wchBuff[1024];

if ( szBegin != szStart )
{
swprintf(wchBuff, L"%.*s", szStart -szBegin, szBegin);
bstrRes += _bstr_t(wchBuff);
}

swprintf(wchBuff, L"%.*s", szEnd -szStart, szStart);

bstrRes += ( _bstr_t(wchBuff) == _bstr_t(L"*") )
? L"[^n]" +_bstr_t(wchBuff) //zero based: first group /analog Perl variable: $2/
: L"[^n]";
}
}
while ( _bstr_t(pEnd) != _bstr_t(L"") );


bstrRes = L"^" +bstrRes +L"$";
return bstrRes;
}

Функции экранирования

Листинг функции



// This function escapes characters and returns the regular expression
// without Metacharacters. For example convert <+1(2)3> to <+1(2)3>.
static _bstr_t utility_ShadeMetacharacters(_bstr_t bstrString, _bstr_t bstrRegExpr = L"")
{
// simbol class [\\|+{}[\]()^$.*?] means:
// \\ - shaded simbol'' (C++ & regular expresion metasimbol)
// \] - shaded simbol']'
// other simbols are '|', '+', '{', '}', '[', '(', ')', '^', '$', '.', '*', '?'
_bstr_t bstrRegExpresion = ( bstrRegExpr ==_bstr_t(L"") )
? L"{[\\|+{}[\]()^$.*?]}" //[*?]
: bstrRegExpr;

CAtlRegExp<> re;
REParseError status = re.Parse(bstrRegExpresion);
if(status != REPARSE_ERROR_OK)
return L"";

const wchar_t* pEnd = bstrString;
_bstr_t bstrRes = L"";

do
{
CAtlREMatchContext<> mc;
const wchar_t *szBegin = pEnd;
if ( !re.Match(pEnd, &mc, &pEnd) )
{
bstrRes += szBegin;
break;
}

if ( mc.m_uNumGroups > 0 )
{
const wchar_t* szStart, * szEnd;
mc.GetMatch(0, &szStart, &szEnd);
if ( szEnd == szStart )
{
bstrString = pEnd;
continue;
}

wchar_t wchBuff[1024];

if ( szBegin != szStart )
{
swprintf(wchBuff, L"%.*s", szStart -szBegin, szBegin);
bstrRes += _bstr_t(wchBuff);
}

swprintf(wchBuff, L"%.*s", szEnd -szStart, szStart);

bstrRes += L"\" +_bstr_t(wchBuff); //zero based: first group /analog Perl variable: $2/

}
}
while ( _bstr_t(pEnd) != _bstr_t(L"
") );
return bstrRes;
}


В заключение

Реализуя свой алгоритм поиска в пользовательском интерфейсе незабудьте вывести информацию о количество найденный слов, потому что если результат поиска более чем 20-30, то нужно сужать границы поиска или конкретизировать шаблон.

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

Список ссылок

  1. Козак Н.В. Использование регулярных выражений для фильтрации ввода.
  2. Регулярные выражения. 2-е изд. /Дж. Фридл.- СПб.: Питер, 2003.- 464 с.: ил. - (Серия "Библиотека программиста"). ISBN 5-272-00331-4.



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