<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=246272&amp;view=findpost&amp;p=2038571</guid>
        <pubDate>Fri, 08 Aug 2008 19:42:08 +0000</pubDate>
        <title>Регулярные выражения</title>
        <link>https://forum.sources.ru/index.php?showtopic=246272&amp;view=findpost&amp;p=2038571</link>
        <description><![CDATA[AndNot: <div class='tag-align-center'><span class='tag-size' data-value='13' style='font-size:13pt;'><span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Регулярные выражения</strong></span></span></div><br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Введение.</strong></span></span></div><br>
Регулярные выражения - это один из способов поиска подстрок (соответствий) в строках. Поиск осуществляется по заданному шаблону, в соответствии с определенными правилами. Самостоятельное создание подобного парсера занятие довольно трудоемкое и долгое, а потому лучше использовать уже существующие. Но, когда мне потребовалось генерировать HTML-файлы, на основе существующих текстовых файлов, неожиданно столкнулся с проблемой, а именно с отсутствием выбора. То есть выбор был, но довольно скудный, который я остановил на VBScript Regular Expression, поставляемый в составе IE, в файле vbscript.dll, начиная с Win9x. Сразу замечу, что существуют две версии Regular Expression. В Win9x, по умолчанию, используется версия 1.0, достаточно функциональная, но не полная. Следующая версия интерфейса (5.5, а не 2.0, как мог кто-то подумать) вышла вместе с IE 5.5 и обладает уже приемлемым функционалом, пригодным для любых задач. Я рассмотрю обе, указывая их отличия по мере необходимости.<br>
Заранее прошу прощения за возможные неточности в терминологии, но я не силен в теории, тем более ООП :D <br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Инструменты.</strong></span></span></div><br>
VBScript Regular Expression написан с использованием технологии COM, поэтому выбор ассемблера напрашивается сам собой - Turbo Assembler, имеющий удобную поддержку ООП. Очень сильно помогла утилита OLEVIEW, из состава Visual Studio, благодаря которой я смог узнать структуру всех используемых интерфейсов и параметры методов. Thanks и создателю OllyDbg, за прекрасный инструмент, без которого данная статья навряд ли бы появилась.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Инициализация.</strong></span></span></div><br>
Для начала любой работы с COM-объектами необходимо инициализировать COM в текущем потоке, создать объект класса и запросить ссылку на экземпляр нужного интерфейса. После работы необходимо уничтожить созданные объекты и деинсталлировать COM в текущем потоке. <br>
Как известно, для создания экземпляра класса, а так же для получения ссылок на любые интерфейсы необходимо знать их уникальные идентификаторы - GUID, вот и начнем с их объявления. Идентификатор класса можно найти в реестре, в ветке <em class='tag-i'>&#092;HKEY_CLASSES_ROOT&#092;CLSID&#092;</em>. Идентификаторы интерфейсов легко определить с помощью OLEVIEW. Таким образом, имеем все необходимое для их объявления: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">; This macro is from Morten Elling&#39;s TaCOM examples, thanks to the author.</div><div class="code_line">macro GUID gName: req, gString:req</div><div class="code_line">&nbsp;&nbsp;local @@byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;label gName byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;irp t, &#60;8,6,4,2, 13,11, 18,16, 21,23, 26,28,30,32,34,36&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@@byte SUBSTR &#60;gString&#62;, t, 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@@byte CATSTR &#60;0&#62;, @@byte, &#60;h&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;db @@byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;endm</div><div class="code_line">endm</div><div class="code_line">&nbsp;</div><div class="code_line">dataseg</div><div class="code_line">&nbsp;&nbsp;; ID класса</div><div class="code_line">&nbsp;&nbsp;GUID CLSID_IRegExp {3F4DACA4-160D-11D2-A8E9-00104B365C9F}</div><div class="code_line">&nbsp;&nbsp;; ID интерфейсов</div><div class="code_line">&nbsp;&nbsp;GUID IID_IRegExp &nbsp; {3F4DACA0-160D-11D2-A8E9-00104B365C9F} &nbsp; &nbsp; ; v 1.0</div><div class="code_line">&nbsp;&nbsp;GUID IID_IRegExp2 &nbsp;{3F4DACB0-160D-11D2-A8E9-00104B365C9F} &nbsp; &nbsp; ; v 5.5</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script>Макрос <em class='tag-i'>GUID</em> создает метку gName и парсит gString, переводя строку в массив байт, который и является уникальным идентификатором. Ничего сложного. <br>
Теперь можно смело переходить к инициализации COM и получению интерфейсов. Оформим это в виде подпрограмм, чтобы больше не возвращаться к этому: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">dataseg</div><div class="code_line">&nbsp;&nbsp;COMInstalled &nbsp;dd 0</div><div class="code_line">&nbsp;</div><div class="code_line">codeseg</div><div class="code_line">&nbsp;</div><div class="code_line">; запрашивает интерфейс @@IID класса @@CLSID</div><div class="code_line">; на входе:</div><div class="code_line">; &nbsp; &nbsp;@@CLSID &nbsp; &nbsp;- GUID запрашиваемого класса</div><div class="code_line">; &nbsp; &nbsp;@@IID &nbsp; &nbsp; &nbsp;- GUID запрашиваемого интерфейса</div><div class="code_line">; на выходе:</div><div class="code_line">; &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp;- ссылка на интерфейс, или NULL в случае ошибки</div><div class="code_line">proc CreateObject uses edx, @@CLSID, @@IID</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;cmp &nbsp; &nbsp; [COMInstalled], 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jne &nbsp; &nbsp; @@create</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;CoInitialize, 0 ; инициализируем COM</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@create:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;inc &nbsp; &nbsp; [COMInstalled]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; создаем объект класса и запрашиваем интерфейс</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем временный буфер, под указатель на запрашиваемый интерфейс</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;CoCreateInstance, [@@CLSID], 0, 5, [@@IID], esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; edx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; edx = LPVOID * ppv</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;or &nbsp; &nbsp; &nbsp;eax, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jns &nbsp; &nbsp; @@done</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; ошибка, уничтожаем COM</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;DestroyObject, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;xor &nbsp; &nbsp; edx, edx</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@done:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;xchg &nbsp; &nbsp;eax, edx &nbsp; &nbsp; &nbsp; &nbsp;; возвращаем результат в EAX</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ret</div><div class="code_line">endp</div><div class="code_line">&nbsp;</div><div class="code_line">; уничтожает объект и, в случае необходимости, деинсталлирует COM в текущем потоке</div><div class="code_line">; на входе:</div><div class="code_line">; &nbsp; &nbsp;@@lpObj &nbsp; &nbsp;- ссылка на экземпляр объекта</div><div class="code_line">; &nbsp; &nbsp;если уничтожили последний объект, то автоматом вызовится CoUninitialize</div><div class="code_line">proc DestroyObject uses edx, @@lpObj</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;cmp &nbsp; &nbsp; [COMInstalled], 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;je &nbsp; &nbsp; &nbsp;@@done</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; edx, [@@lpObj]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;or &nbsp; &nbsp; &nbsp;edx, edx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jz &nbsp; &nbsp; &nbsp;@@isuninst</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IUnknown edx METHOD IUnknown:Release USES ds:eax, edx</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@isuninst:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dec &nbsp; &nbsp; [COMInstalled]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jnz &nbsp; &nbsp; @@done</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;CoUninitialize</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@done:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ret</div><div class="code_line">endp</div></ol></div></div></div></div>Пояснять здесь нечего, все ясно из комментариев, обычный код инициализации, получения интерфейса и завершения работы с COM, пригодный для работы с любыми COM-объектами. Тонкость только в одном, как только программа удаляет все ссылки на интерфейсы, то автоматически происходит деинициализация COM в текущем потоке. Это сделано только из соображений удобства, но можно сделать и без &quot;автоматики&quot;.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Строки.</strong></span></span></div><br>
Поскольку регулярные выражения применяются в основном для обработки строк, то сразу определимся с их форматом, для лучшего понимания последующих примерчиков. Дело в том, что VBScript, как не трудно догадаться из названия, использует тот же тип строк, что и Visual Basic, так называемый <em class='tag-i'>BSTR</em>. Это обычные Unicode-строки, со счетчиком длины, который имеет размер в двойное слово. Но, в отличие от привычных Паскаль-строк, указатель на строку указывает на первый символ строки, а не на счетчик длины&#33; Таким образом, их можно использовать и как строки с завершающим нулем. Но нам удобнее работать в ANSI-режиме, преимущества которого очевидны во многих случаях, особенно при интенсивной работе с файлами и консолью, поэтому создадим парочку подпрограмм, для конвертирования ANSI&lt;--&#62;BSTR: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">; конвертирует ANSI строку в BSTR(unicode)</div><div class="code_line">; возвращает указатель на сформированную строку</div><div class="code_line">proc ANSItoBSTR uses ebx, @@ansistr</div><div class="code_line">&nbsp;&nbsp;local @@lena, @@lenw</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;lstrlenA, [@@ansistr]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; [@@lena], eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;inc &nbsp; &nbsp; eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; резервируем место для завершающего нуля</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;shl &nbsp; &nbsp; eax, 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; eax = eax*2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; [@@lenw], eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;GlobalAlloc, 0, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;or &nbsp; &nbsp; &nbsp;eax, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jz &nbsp; &nbsp; &nbsp;@@done</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; ebx, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;MultiByteToWideChar, 0, 0, [@@ansistr], [@@lena], eax, [@@lenw]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysAllocStringLen, ebx, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;GlobalFree, ebx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; eax</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@done:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ret</div><div class="code_line">endp</div><div class="code_line">&nbsp;</div><div class="code_line">; конвертирует BSTR строку в ANSI</div><div class="code_line">; возвращает указатель на сформированную строку</div><div class="code_line">proc BSTRtoANSI uses edx, @@lpBStr</div><div class="code_line">&nbsp;&nbsp;local @@len</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;lstrlenW, [@@lpBStr]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;inc &nbsp; &nbsp; eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; резервируем место для завершающего нуля</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; [@@len], eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;GlobalAlloc, 0, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;or &nbsp; &nbsp; &nbsp;eax, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jz &nbsp; &nbsp; &nbsp;@@done</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;xor &nbsp; &nbsp; edx, edx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;WideCharToMultiByte, edx, edx, [@@lpBStr], -1, eax, [@@len], edx, edx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; eax</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@done:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ret</div><div class="code_line">endp</div></ol></div></div></div></div>Функция <em class='tag-i'>ANSItoBSTR</em> принимает указатель на строку в ANSI-кодировке, выделяет память и переводит строку в Unicode, посредством <em class='tag-i'>MultiByteToWideChar</em>, а уж затем переводит Unicode-строку в BSTR, возвращая адрес последней в регистре EAX. <em class='tag-i'>BSTRtoANSI</em> выполняет обратную функцию, возвращая указатель на ANSI-строку. Вообще же хочу заметить, что данные функции далеко не оптимальны и годятся только для примера. В частности, перевод Unicode-строки в BSTR лучше осуществлять самим, без использования <em class='tag-i'>SysAllocStringLen</em>, так же определение длины BSTR-строки лучше делать чтением счетчика длины, а не как у меня через <em class='tag-i'>lstrlenW</em>. Просто для большей наглядности я оставил использование WinAPI :) <br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Интерфейсы.</strong></span></span></div><br>
Regular Expression предоставляет четыре интерфейса. Вся работа по поиску и замене сосредоточена в одном, а остальные три являются вспомогательными:<br>
<strong class='tag-b'><span class="tag-color tag-color-named" data-value="blue" style="color: blue">IRegExp</span></strong> - основной интерфейс, реализующий все функции поиска, замены и выборки соответствий по заданному шаблону.<br>
<strong class='tag-b'><span class="tag-color tag-color-named" data-value="blue" style="color: blue">IMatchCollection</span></strong> - вспомогательный интерфейс, содержит коллекцию найденных соответствий, хранимых в виде массива объектов <em class='tag-i'>IMatch</em>.<br>
<strong class='tag-b'><span class="tag-color tag-color-named" data-value="blue" style="color: blue">IMatch</span></strong> - вспомогательный интерфейс, используется для хранения одного найденного соответствия.<br>
<strong class='tag-b'><span class="tag-color tag-color-named" data-value="blue" style="color: blue">ISubMatches</span></strong> - вспомогательный интерфейс, появился в версии 5.5, содержит коллекцию субсоответствий, то есть как бы соответствие в соответствии.<br>
Все эти интерфейсы являются потомками интерфейса <span class="tag-color tag-color-named" data-value="blue" style="color: blue">IDispatch</span>, который в свою очередь является потомком <span class="tag-color tag-color-named" data-value="blue" style="color: blue">IUnknown</span>, базового интерфейса всех объектов, согласно COM-технологии. Так что вполне логично начать именно с их объявления: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">struc IUnknown METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual QueryInterface &nbsp; ; ([in] GUID* riid, [out] void** ppvObj)</div><div class="code_line">&nbsp;&nbsp;virtual AddRef &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ()</div><div class="code_line">&nbsp;&nbsp;virtual Release &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; ()</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div><div class="code_line">&nbsp;</div><div class="code_line">struc IDispatch IUnknown METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual GetTypeInfoCount ; ([out] unsigned int* pctinfo)</div><div class="code_line">&nbsp;&nbsp;virtual GetTypeInfo &nbsp; &nbsp; &nbsp;; [in] unsigned int itinfo, [in] unsigned long lcid, [out] void** pptinfo)</div><div class="code_line">&nbsp;&nbsp;virtual GetIDsOfNames &nbsp; &nbsp;;</div><div class="code_line">&nbsp;&nbsp;virtual Invoke &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div></ol></div></div></div></div>Для тех, кто не знаком с Turbo Assembler, поясню. Ключевое слово <em class='tag-i'>METHOD</em> показывает, что мы используем расширенную форму директивы <em class='tag-i'>STRUC</em> для описания объекта. Далее, в фигурных скобках, следуют описания методов объекта. Ключевое слово <em class='tag-i'>VIRTUAL</em> указывает, что вызов метода следует производить косвенно, через таблицу VMT(Virtual Method Table). Далее следует имя метода. То есть в данном случае будет просто объявлена таблица VMT, каждому методу будет присвоено смещение в этой таблице, но экземпляр таблицы создаваться не будет, что собственно и требовалось.<br>
Затем объявляем объект <em class='tag-i'>IDispatch</em>, но уже в качестве потомка <em class='tag-i'>IUnknown</em>, что автоматом добавит в его таблицу VMT все методы <em class='tag-i'>IUnknown</em>. Еще отмечу, что параметры методов указаны в комментариях, в том виде, в котором их выдает OLEVIEW, что довольно удобно, но не дает полной картины правильной передачи параметров в методы. В квадратных скобках находится уточнение о типе параметра - входящие(in) или возвращаемые(out) значения.<br>
Более подробно описывать эти интерфейсы нет смысла, первый описан в любом учебнике по COM-технологии, а второй напрямую не относится к теме и используется для вызова методов по их именам, что нам не пригодится.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Интерфейс IRegExp.</strong></span></span></div><br>
Это основной интерфейс, предоставляющий базовые методы для работы с регулярными выражениями. Всего интерфейс предоставляет три (для версии 5.5 - четыре) свойства и три метода. <br>
<span class='tag-u'><strong class='tag-b'>Свойства</strong></span>:<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Pattern</strong></span> - строка с регулярным выражением, являющаяся шаблоном для поиска подстрок. Обязательно должна быть задана до первого использования любых методов объекта. <br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>IgnoreCase</strong></span> - булевое значение. Если задано TRUE(-1), то при поиске соответствий игнорируется регистр символов. По умолчанию имеет значение FALSE, как и остальные свойства.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Global</strong></span> - булевое значение. Если TRUE, то будут искаться все возможные соответствия в строке. При значении FALSE поиск остановится после первого найденного соответствия.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Multiline</strong></span> - булевое значение, появилось в версии 5.5. Значение TRUE соответствует многострочному поиску, т.е. учитываются переносы строк. В противном случае исходная строка рассматривается просто как набор символов. В принципе можно обойтись и без этого свойства, указывая начало и конец строк в шаблоне поиска, но все же отказываться от него не стоит, так проще.<br>
<span class='tag-u'><strong class='tag-b'>Методы</strong></span>:<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Test</strong></span> - ищет в строке соответствия заданному шаблону поиска, в случае успеха возвращает TRUE.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Execute</strong></span> - то же, что и предыдущий метод, но с одним существенным отличием - все найденные соответствия будут помещены в коллекцию <em class='tag-i'>IMatchCollection</em>.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Replace</strong></span> - ищет в строке соответствия заданному шаблону и заменяет их на строку, заданную в параметрах. При замене возможна примитивная обработка результатов поиска.<br>
Учитывая тот факт, что свойства являются ни чем иным как простыми методами, для чтения/записи некоторых внутренних данных объекта, структура интерфейса будет выглядеть следующим образом: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">; version 1.0</div><div class="code_line">struc IRegExp IDispatch METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual GetPattern &nbsp; &nbsp; &nbsp; ; [out, retval] BSTR* pPattern</div><div class="code_line">&nbsp;&nbsp;virtual SetPattern &nbsp; &nbsp; &nbsp; ; [in] BSTR pPattern</div><div class="code_line">&nbsp;&nbsp;virtual GetIgnoreCase &nbsp; &nbsp;; [out, retval] VARIANT_BOOL* pIgnoreCase</div><div class="code_line">&nbsp;&nbsp;virtual SetIgnoreCase &nbsp; &nbsp;; [in] VARIANT_BOOL pIgnoreCase</div><div class="code_line">&nbsp;&nbsp;virtual GetGlobal &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] VARIANT_BOOL* pGlobal</div><div class="code_line">&nbsp;&nbsp;virtual SetGlobal &nbsp; &nbsp; &nbsp; &nbsp;; [in] VARIANT_BOOL pGlobal</div><div class="code_line">&nbsp;&nbsp;virtual Execute &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [in] BSTR sourceString, [out, retval] IDispatch** ppMatches</div><div class="code_line">&nbsp;&nbsp;virtual Tests &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [in] BSTR sourceString, [out, retval] VARIANT_BOOL* pMatch</div><div class="code_line">&nbsp;&nbsp;virtual Replace &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [in] BSTR sourceString, [in] VARIANT replaceVar, [out, retval] BSTR* pDestString</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div><div class="code_line">&nbsp;</div><div class="code_line">; version 5.5</div><div class="code_line">struc IRegExp2 IDispatch METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual GetPattern &nbsp; &nbsp; &nbsp; ; [out, retval] BSTR* pPattern</div><div class="code_line">&nbsp;&nbsp;virtual SetPattern &nbsp; &nbsp; &nbsp; ; [in] BSTR pPattern</div><div class="code_line">&nbsp;&nbsp;virtual GetIgnoreCase &nbsp; &nbsp;; [out, retval] VARIANT_BOOL* pIgnoreCase</div><div class="code_line">&nbsp;&nbsp;virtual SetIgnoreCase &nbsp; &nbsp;; [in] VARIANT_BOOL pIgnoreCase</div><div class="code_line">&nbsp;&nbsp;virtual GetGlobal &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] VARIANT_BOOL* pGlobal</div><div class="code_line">&nbsp;&nbsp;virtual SetGlobal &nbsp; &nbsp; &nbsp; &nbsp;; [in] VARIANT_BOOL pGlobal</div><div class="code_line">&nbsp;&nbsp;virtual GetMultiline &nbsp; &nbsp; ; [out, retval] VARIANT_BOOL* pMultiline</div><div class="code_line">&nbsp;&nbsp;virtual SetMultiline &nbsp; &nbsp; ; [in] VARIANT_BOOL pMultiline</div><div class="code_line">&nbsp;&nbsp;virtual Execute &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [in] BSTR sourceString, [out, retval] IDispatch** ppMatches</div><div class="code_line">&nbsp;&nbsp;virtual Tests &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [in] BSTR sourceString, [out, retval] VARIANT_BOOL* pMatch</div><div class="code_line">&nbsp;&nbsp;virtual Replace &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [in] BSTR sourceString, [in] VARIANT replaceVar, [out, retval] BSTR* pDestString</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div></ol></div></div></div></div>Для всех методов, как того и требует стандарт СОМ, справедливо соглашение о возвращаемом в регистре EAX значении. Если вернуло NULL, то функция выполнилась успешно, в противном случае нужно анализировать отдельные биты, для установления причин ошибки, в самом простом случае достаточно проанализировать старший бит.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Свойства интерфейса IRegExp.</strong></span></span></div><br>
Кто внимательно читал статью, тот помнит, что свойства интерфейса влияют на условия поиска соответствий. Изменять их значения можно с помощью методов <em class='tag-i'>SetGlobal</em>, <em class='tag-i'>SetIgnoreCase</em> и <em class='tag-i'>SetMultiline</em>, которые принимают один параметр типа BOOL. Вот и первый сюрприз Вижен Бейсика - булевые типы имеют размер в слово, но при использовании  их в качестве параметров на стэке, используются разумеется двойные слова&#33; Вызовы методов выглядят следующим образом: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetGlobal USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetIgnoreCase USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetMultiline USES ds:eax, ebx, -1</div></ol></div></div></div></div>Тем, кто не знаком с Turbo Assembler, этот код покажется бредом, поэтому поясню. Поддержка ООП в Turbo Assembler выражена не только созданием/наследованием структур и объявлением методов, но и вызовом этих методов. Причем, в зависимости от объявления, метод может вызываться как статичный, так и как виртуальный. Дело в том, что еще при объявлении объектов, помимо структуры данных объекта, создается таблица методов объекта, в которой запоминается вся необходимая информация о методе, позволяющая компилятору корректно вызывать этот метод. Синтаксис расширенной формы CALL достаточно гибок, поэтому приведу лишь небольшую упрошенную модель вызова методов объектов, достаточную для понимая дальнейших примеров:<br>
<em class='tag-i'>CALL</em> &lt;class&gt; &lt;instance&gt; <em class='tag-i'>METHOD</em> [class:]&lt;method&gt; [<em class='tag-i'>USES</em> segreg:reg] [mode][, parameters]<br>
где:<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue">class</span> - имя объекта.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue">instance</span> - указатель на экземпляр объекта.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue">method</span> - разумеется имя вызываемого метода.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue">USES</span> - определяет временный регистр, используемый для вызова виртуальных методов.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue">mode</span> - соглашение о модели вызова подпрограммы (C, Pascal, StdCall и т.д.), позволяющее переопределить текущую модель (заданную директивой <em class='tag-i'>MODEL</em>) для данного вызова.<br>
<span class="tag-color tag-color-named" data-value="blue" style="color: blue">parameters</span> - параметры, разделенные либо запятой, либо пробелами, пишущиеся, как и в языках высокого уровня, слева направо, но ложиться в стэк они будут в порядке, определенным директивой <em class='tag-i'>MODEL</em>, либо в порядке заданным <em class='tag-i'>mode</em>.<br>
Думаю тут все ясно, осталось только уточнить назначение ключевого слова <em class='tag-i'>USES</em>. Это слово сам Том Сван, в своей замечательной книге &quot;<em class='tag-i'>Освоение Turbo Assembler</em>&quot; истолковал неверно, сделав совершенно ошибочные выводы, оно и понятно, документация на tasm была крайне кривой :) Для его правильного толкования рассмотрим вызов виртуального метода: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">; ebx - указатель на экземпляр объекта</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; &nbsp;eax, [ebx] &nbsp; &nbsp; ; eax - адрес таблицы виртуальных методов (VMT)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp; 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; параметры</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp; ebx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; push Self/This</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp; [eax+смещение_метода_в_VMT]</div></ol></div></div></div></div>Как видно вызов происходит в три этапа, на первом мы получаем адрес VMT, на втором заносим в стэк параметры, а на заключительном вызываем нужный метод, беря его адрес из таблицы VMT. Очевидно, что для данного вызова необходимо два регистра - на указатель экземпляра объекта и временный, под указатель на VMT. Указатель на экземпляр объекта мы указываем явно, в параметрах <em class='tag-i'>CALL...METHOD</em>, а как компилятору узнать, какой регистр можно использовать как временный, чтобы не испортить его содержимое? Правильно, его мы указываем после ключевого слова <em class='tag-i'>USES</em>, причем в паре с сегментным регистром. Если же эту директиву пропустить, то в качестве временного будет использоваться пара <em class='tag-i'>ES:EBX</em>, что довольно не удобно.<br>
Таким образом, вызов: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetGlobal USES ds:edx, ebx, -1</div></ol></div></div></div></div>будет развернут компилятором в следующую последовательность: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; &nbsp;edx, [ebx] &nbsp; &nbsp; ; edx = addr VMT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp; -1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp; ebx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; push Self|This</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp; [ds:edx+30h] &nbsp; ; call [VMT+30h]</div></ol></div></div></div></div>Где 30h - это смещение данного метода в таблице VMT объекта. Тут нужно обратить внимание на то, что первым параметром любых методов всегда указывается указатель на экземпляр объекта, в данном случае регистр EBX. Его приходится передавать через стек, поскольку это недостаток кривой реализации ООП в языках высокого уровня, где этот параметр &quot;не видим&quot; и передается через стэк. Это так называемые <em class='tag-i'>Self</em> в Паскале/Дельфи и <em class='tag-i'>this</em> в C++.<br>
Свойства можно не только задавать, но и получить их состояние вызовом методов <em class='tag-i'>GetGlobal</em>, <em class='tag-i'>GetIgnoreCase</em> и <em class='tag-i'>GetMultiline</em>, которым передается указатель на переменную типа BOOL. Например, получить состояния свойства <em class='tag-i'>Global</em> можно так: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем временный буфер в стеке</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD GetGlobal USES ds:eax, ebx, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; edx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; dx - полученное значение свойства объекта (word)</div></ol></div></div></div></div>здесь переменная создается в стэке, что иногда предпочтительнее, нежели ее хранение в сегменте данных. Только не стоит забывать, что значение BOOL, имеет размер в слово, что необходимо учитывать при обработке полученного результата&#33; <br>
Осталось рассмотреть еще одно свойство - <em class='tag-i'>Pattern</em>. Это свойство имеет тип BSTR и предназначено для хранения шаблона поиска. Шаблон задается через метод <em class='tag-i'>SetPattern</em>, имеющий один параметр - указатель на BSTR-строку шаблона. Получить указатель на текущий шаблон можно с помощью метода <em class='tag-i'>GetPattern</em>, которому передается указатель на двойное слово, куда и будет записан адрес BSTR-строки шаблона. Например: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">dataseg</div><div class="code_line">&nbsp;&nbsp;szPattern &nbsp; &nbsp; &nbsp;db &#39;^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$&#39;, 0</div><div class="code_line">&nbsp;</div><div class="code_line">codeseg</div><div class="code_line">; &nbsp; &nbsp; &nbsp; .....</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; задаем шаблон поиска соответствий</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szPattern &nbsp; &nbsp;; готовим BSTR-строку шаблона поиска соответствий</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetPattern USES ds:edx, ebx, eax</div><div class="code_line">&nbsp;</div><div class="code_line">; &nbsp; &nbsp; &nbsp; .....</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; получаем текущий шаблон поиска соответствий</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем временный буфер под указатель на строку шаблона</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD GetPattern USES ds:eax, ebx, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; eax - адрес BSTR-строки шаблона</div></ol></div></div></div></div>Думаю из комментариев все ясно. Причем, если посмотреть под отладчиком, то увидим, что <em class='tag-i'>GetPattern</em> возвращает адрес строки, который мы задали свойству через <em class='tag-i'>SetPattern</em>, что говорит о том, что память, отведенную под строку шаблона, нельзя освобождать до тех пор, пока эта строка используется в качестве шаблона.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Метод Test.</strong></span></span></div><br>
Для тестирования строки на соответствие шаблону предназначен метод <em class='tag-i'>Test</em>. Он просто ищет соответствие по заданному шаблону и возвращает булевое значение TRUE, если соответствие найдено, или FALSE, если таковых не имеется. Метод принимает два параметра, указатель на строку, в которой ищется соответствие и указатель на переменную типа BOOL, в которую будет записан результат поиска. Шаблон поиска уже должен находиться в свойстве <em class='tag-i'>Pattern</em>. В качестве примера можно рассмотреть тестирование строки на предмет соответствия ее содержимого вещественному или целому числу: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">; file: test.asm</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ideal</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;p586</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;model flat, stdcall</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;locals @@</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;%NOINCL</div><div class="code_line">&nbsp;</div><div class="code_line">include &#39;kernel32.inc&#39;</div><div class="code_line">include &#39;regexpr.inc&#39;</div><div class="code_line">include &#39;ole32.inc&#39;</div><div class="code_line">include &#39;oleaut32.inc&#39;</div><div class="code_line">&nbsp;</div><div class="code_line">includelib &#39;imp32i.lib&#39;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;</div><div class="code_line">dataseg</div><div class="code_line">&nbsp;&nbsp;; ID класса и интерфейсов</div><div class="code_line">&nbsp;&nbsp;GUID CLSID_IRegExp {3F4DACA4-160D-11D2-A8E9-00104B365C9F}</div><div class="code_line">&nbsp;&nbsp;GUID IID_IRegExp &nbsp; {3F4DACA0-160D-11D2-A8E9-00104B365C9F} &nbsp; &nbsp; ; v 1.0</div><div class="code_line">&nbsp;&nbsp;GUID IID_IRegExp2 &nbsp;{3F4DACB0-160D-11D2-A8E9-00104B365C9F} &nbsp; &nbsp; ; v.5.5</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;; тестовые строки, содержащие &quot;числа&quot;</div><div class="code_line">&nbsp;&nbsp;szTest1 &nbsp; &nbsp; &nbsp; db &#39;+12E-2&#39;, 0</div><div class="code_line">&nbsp;&nbsp;szTest2 &nbsp; &nbsp; &nbsp; db &#39;02+E-a&#39;, 0</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;; шаблон для поиска</div><div class="code_line">&nbsp;&nbsp;szPatNum &nbsp; &nbsp; &nbsp;db &#39;^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$&#39;, 0</div><div class="code_line">&nbsp;</div><div class="code_line">codeseg</div><div class="code_line">&nbsp;&nbsp; &nbsp;Begin: &nbsp;; program entry point ...</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; инициализируем COM и получаем экземпляр объекта RegExp2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;CreateObject, lpCLSID_IRegExp, lpIID_IRegExp2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_error &nbsp;nz, &quot;Sorry, this programm request VBScript Regular Expression ver 5.5 or later!&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; ebx, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; настраиваем свойства объекта</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetGlobal USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetIgnoreCase USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetMultiline USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; задаем шаблон поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szPatNum</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetPattern USES ds:edx, ebx, eax</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; подготавливаем строку для поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szTest1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; сохраняем указатель на BSTR, для SysFreeString</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; проверяем строку на соответствие шаблону</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем временный буфер для результата поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD Test USES ds:edx, ebx, eax, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ax - булевое значение, результат поиска соответствия</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;movsx &nbsp; eax, ax &nbsp; &nbsp; &nbsp; &nbsp; ; расширяем слово до двойного слова со знаком</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_printf &#60;&quot;Source string: %s&quot;,13,10,&quot;Result: %i&quot;,13,10&#62;, offset szTest1, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysFreeString &nbsp; ; удаляем BSTR строку</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; подготавливаем строку для поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szTest2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; сохраняем указатель на BSTR, для SysFreeString</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; проверяем строку на соответствие шаблону</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем временный буфер для результата поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD Test USES ds:edx, ebx, eax, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ax - булевое значение, результат поиска соответствия</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;movsx &nbsp; eax, ax &nbsp; &nbsp; &nbsp; &nbsp; ; расширяем слово до двойного слова со знаком</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_printf &#60;&quot;Source string: %s&quot;,13,10,&quot;Result: %i&quot;,13,10&#62;, offset szTest2, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysFreeString &nbsp; ; удаляем BSTR строку</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; уничтожаем строку шаблона</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем временный буфер под указатель на строку шаблона</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD GetPattern USES ds:eax, ebx, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysFreeString &nbsp; ; освобождаем память</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; уничтожаем объект и завершаем COM в текущем потоке</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;DestroyObject, ebx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; ждем нажатия любой клавиши и завершаем программу</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;_getch</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ExitProcess, 0</div><div class="code_line">end Begin</div></ol></div></div></div></div>Как видно тестируются две строки по одному шаблону. Сам шаблон подходит под определение, как целых, так и вещественных чисел. И если запустить этот пример, то увидим следующее: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Source string: +12E-2</div><div class="code_line">Result: -1</div><div class="code_line">Source string: 02+E-a</div><div class="code_line">Result: 0</div></ol></div></div></div></div>Все правильно, последнее число написано с ошибкой.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Метод Replace.</strong></span></span></div><br>
Теперь можно попробовать и замену. Если требуемая замена несложная, то лучше всего использовать метод <em class='tag-i'>Replace</em>, специально для этого и предназначенный. Он принимает три параметра: первым является указатель на BSTR-строку, в которой и будет производиться поиск соответствий шаблону, вторым параметром является переменная типа <em class='tag-i'>VARIANT</em>, в которой описываются условия замены, ну а третьим параметром будет указатель на область памяти, куда метод вернет указатель на результатирующую BSTR-строку. Шаблон поиска соответствий указывается в свойстве Pattern.<br>
Казалось бы, все легко и просто, но во втором параметре есть засада :) Для начала смотрим определение типа <em class='tag-i'>VARIANT</em>: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">struc VARIANT</div><div class="code_line">&nbsp;&nbsp;vt &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dw ?</div><div class="code_line">&nbsp;&nbsp;wReserved1 &nbsp; &nbsp;dw ?</div><div class="code_line">&nbsp;&nbsp;wReserved2 &nbsp; &nbsp;dw ?</div><div class="code_line">&nbsp;&nbsp;wReserved2 &nbsp; &nbsp;dw ?</div><div class="code_line">&nbsp;&nbsp;datas &nbsp; &nbsp; &nbsp; &nbsp; dd ?</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd ?</div><div class="code_line">ends</div></ol></div></div></div></div>Поле <em class='tag-i'>vt</em> определяет тип данных. Я пробовал только <em class='tag-i'>VT_BSTR</em>, значением которой является 8. Поле <em class='tag-i'>datas</em> содержит либо данные, либо ссылку на них. Поскольку у нас строки, то в это поле заносится ссылка на строку. Остальные поля содержат нули. А засада в том, что вопреки здравому смыслу эта структура передается не по ссылке, а непосредственно через стэк. При этом поля размером в слово &quot;склеиваются&quot; попарно, то есть, поскольку <em class='tag-i'>vt</em> и <em class='tag-i'>wReserved1</em> имею размер в слово, то передаем их вместе, как одно двойное слово, ну и с остальными поступаем так же. Маразм конечно, но это не я придумал, это тяжелое наследство 16-ти разрядного Вижен Бейсика :D <br>
В качестве примера рассмотрим замену сишных объявлений констант на ассемблерные, хотя и в ограниченном варианте: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">dataseg</div><div class="code_line">&nbsp;&nbsp;; исходный текст</div><div class="code_line">&nbsp;&nbsp;szCode &nbsp; &nbsp; &nbsp; &nbsp;db &#39;#define RIGHT_ALT_PRESSED &nbsp; &nbsp; 0x0001&#39;, 13, 10</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;#define LEFT_ALT_PRESSED &nbsp; &nbsp; &nbsp;0x0002&#39;, 13, 10</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;#define RIGHT_CTRL_PRESSED &nbsp; &nbsp;0x0004&#39;, 13, 10</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;#define LEFT_CTRL_PRESSED &nbsp; &nbsp; 0x0008&#39;, 13, 10</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;#define NLS_ALPHANUMERIC &nbsp; &nbsp; &nbsp;0x00000000&#39;, 13, 10</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;#define NLS_KATAKANA &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00020000&#39;, 13, 10</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db 0</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;; шаблон для поиска</div><div class="code_line">&nbsp;&nbsp;szPattern &nbsp; &nbsp; db &#39;^(#define)(\s+)(\w+\s+)(0x)([a-fA-F0-9]{1,8})&#39;, 0</div><div class="code_line">&nbsp;&nbsp;; шаблон замены</div><div class="code_line">&nbsp;&nbsp;szReplace &nbsp; &nbsp; db &#39;equ 0h&#39;, 0</div><div class="code_line">&nbsp;</div><div class="code_line">codeseg</div><div class="code_line">; .........</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; задаем шаблон поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szPattern</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetPattern USES ds:edx, ebx, eax</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; подготавливаем строку для поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szCode</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; esi, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; подготавливаем строку для замены найденных соответствий</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szReplace</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; сохраняем адрес для SysFreeString</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; вызываем метод Replace</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем место под результат</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD Replace USES ds:edx, ebx, esi, 8, 0, eax, 0, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;BSTRtoANSI &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; переводим в ANSI</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; сохраняем адрес для GlobalFree</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; вводим на экран исходный текст и результат замены</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_printf &#60;&quot;Source:&quot;,13,10,&quot;%s&quot;,13,10,&quot;Dest:&quot;,13,10,&quot;%s&quot;,13,10&#62;, offset szCode, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;GlobalFree &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; освобождаем ANSI-строку</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysFreeString &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; освобождаем BSTR-строку szReplace</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysFreeString, esi &nbsp; &nbsp; &nbsp;; освобождаем BSTR-строку szCode</div></ol></div></div></div></div>Здесь хочу обратить внимание только на одну вещь, а именно передачу переменной <em class='tag-i'>VARIANT</em>, которая передается как <span class='tag-u'>четыре</span> двойных слова (8, 0, eax, 0). В остальном коде ничего необычного нет. Строка шаблона, благодаря наличию скобок, разбивает найденное соответствие на пять подстрок, именуемых как &#036;1, &#036;2, &#036;3 и тд. Но в строке szReplace используются только две подстроки (&#036;3 и &#036;5), а остальные отбрасываются. Поэтому, после замены получим следующий результат: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Source:</div><div class="code_line">#define RIGHT_ALT_PRESSED &nbsp; &nbsp; 0x0001</div><div class="code_line">#define LEFT_ALT_PRESSED &nbsp; &nbsp; &nbsp;0x0002</div><div class="code_line">#define RIGHT_CTRL_PRESSED &nbsp; &nbsp;0x0004</div><div class="code_line">#define LEFT_CTRL_PRESSED &nbsp; &nbsp; 0x0008</div><div class="code_line">#define NLS_ALPHANUMERIC &nbsp; &nbsp; &nbsp;0x00000000</div><div class="code_line">#define NLS_KATAKANA &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00020000</div><div class="code_line">&nbsp;</div><div class="code_line">Dest:</div><div class="code_line">RIGHT_ALT_PRESSED &nbsp; &nbsp; equ 00001h</div><div class="code_line">LEFT_ALT_PRESSED &nbsp; &nbsp; &nbsp;equ 00002h</div><div class="code_line">RIGHT_CTRL_PRESSED &nbsp; &nbsp;equ 00004h</div><div class="code_line">LEFT_CTRL_PRESSED &nbsp; &nbsp; equ 00008h</div><div class="code_line">NLS_ALPHANUMERIC &nbsp; &nbsp; &nbsp;equ 000000000h</div><div class="code_line">NLS_KATAKANA &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;equ 000020000h</div></ol></div></div></div></div>Это только простейший пример, для создания полноценного конвертера сишных хидеров нужно несколько проходов.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Метод Execute.</strong></span></span></div><br>
Этот метод предназначен для поиска, с анализом и последующей обработкой найденных соответствий. Методу передаются два параметра. Указатель на BSTR-строку, в которой будет производиться поиск и указатель на переменную, под возвращаемое значение, которое является ни чем иным, как ссылкой на объект <em class='tag-i'>IMatchCollection</em>, в котором и хранятся все найденные соответствия. Интерфейс <em class='tag-i'>IMatchCollection</em> несложен: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">struc IMatchCollection IDispatch METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual Item &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; [in] long index, [out, retval] IDispatch** ppMatch</div><div class="code_line">&nbsp;&nbsp;virtual Count &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] long* pCount</div><div class="code_line">&nbsp;&nbsp;virtual NewEnum &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] IUnknown** ppEnum</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div></ol></div></div></div></div>Как уже упоминалось, этот объект хранит все найденные соответствия, в виде массива объектов <em class='tag-i'>IMatch</em>, по одному объекту на каждое соответствие. Метод <em class='tag-i'>Count</em> возвращает общее количество найденных соответствий. Метод <em class='tag-i'>Item</em> позволяет получить ссылку на нужное соответствие. Он принимает два параметра, индекс, лежащий в диапазоне от 0 до <em class='tag-i'>Count</em>-1, а так же адрес переменной, куда будет записана ссылка на объект <em class='tag-i'>IMatch</em>, соответствующий индексу. Метод <em class='tag-i'>NewEnum</em> не исследовал. Интерфейс <em class='tag-i'>IMatch</em> существует в двух вариантах, в зависимости от версии RegExp: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">; version 1.0</div><div class="code_line">struc IMatch IDispatch METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] BSTR* pValue</div><div class="code_line">&nbsp;&nbsp;virtual FirstIndex &nbsp; &nbsp; &nbsp; ; [out, retval] long* pFirstIndex</div><div class="code_line">&nbsp;&nbsp;virtual Length &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; [out, retval] long* pLength</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div><div class="code_line">&nbsp;</div><div class="code_line">; version 5.5</div><div class="code_line">struc IMatch2 IDispatch METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] BSTR* pValue</div><div class="code_line">&nbsp;&nbsp;virtual FirstIndex &nbsp; &nbsp; &nbsp; ; [out, retval] long* pFirstIndex</div><div class="code_line">&nbsp;&nbsp;virtual Length &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; [out, retval] long* pLength</div><div class="code_line">&nbsp;&nbsp;virtual SubMatches &nbsp; &nbsp; &nbsp; ; [out, retval] IDispatch** ppSubMatches</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div></ol></div></div></div></div>Как видно разница только в методе <em class='tag-i'>SubMatches</em>. Метод <em class='tag-i'>Value</em> возвращает указатель на строку найденного соответствия. Метод <em class='tag-i'>FirstIndex</em> вернет позицию найденного соответствия в искомой строке. Метод <em class='tag-i'>Length</em> возвратит длину найденной строки. Метод <em class='tag-i'>SubMatches</em> доступен начиная с версии RegExp 5.5, и возвращает ссылку на объект <em class='tag-i'>ISubMatches</em>, в котором хранятся субсоответствия, заданные с помощью круглых скобок. Для примера, допустим, есть следующий шаблон поиска: &quot;<em class='tag-i'>(0x)([0-9]+)</em>&quot;. Тогда в строке &quot;<em class='tag-i'>#define CONST 0x012</em>&quot; будет найдено одно соответствие: &quot;<em class='tag-i'>0x012</em>&quot;, которое будет храниться в экземпляре <em class='tag-i'>IMatch</em>, ссылку на который можно получить по нулевому индексу посредством метода <em class='tag-i'>Item</em>, объекта <em class='tag-i'>IMatchCollection</em>. В свою очередь, благодаря наличию круглых скобок, данное соответствие будет разбито на два субсоответствия: &quot;<em class='tag-i'>0x</em>&quot; и &quot;<em class='tag-i'>012</em>&quot;, которые и сохранятся в объекте <em class='tag-i'>ISubMatches</em>. Интерфейс <em class='tag-i'>ISubMatches</em> выглядит следующим образом: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">struc ISubMatches IDispatch METHOD {</div><div class="code_line">&nbsp;&nbsp;virtual Item &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; [in] long index, [out, retval] VARIANT* pSubMatch</div><div class="code_line">&nbsp;&nbsp;virtual Count &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] long* pCount</div><div class="code_line">&nbsp;&nbsp;virtual NewEnum &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; [out, retval] IUnknown** ppEnum</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">ends</div></ol></div></div></div></div>Метод <em class='tag-i'>Count</em> вернет количество субсоответствий. Все субсоответствия хранятся в виде массива, доступ к элементам которого осуществляется через метод <em class='tag-i'>Item</em>, которому передается индекс элемента, лежащий в диапазоне от 0 до <em class='tag-i'>Count</em>-1, и указатель на переменную <em class='tag-i'>VARIANT</em>, в которой и будет возвращено субсоответствие. То есть, в поле <em class='tag-i'>vt</em> будет тип субсоответствия (для BSTR, <em class='tag-i'>vt</em> = 8), а в поле <em class='tag-i'>datas</em> содержится либо ссылка (для строк), либо непосредственные данные.<br>
Выглядит все это немного запутано, поэтому покажу на примере. Допустим, имеется полный путь к некоторому файлу. С помощью метода <em class='tag-i'>Execute</em> очень легко разделить строку на три компоненты: диск, путь и имя файла. А уж затем можно делать с ними, что душе угодно. Итак, некие пути к файлам: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">dataseg</div><div class="code_line">&nbsp;&nbsp;szFiles &nbsp; &nbsp; &nbsp; db &#39;&quot;E:\Program Files\Tasm\Project\RegExpr\exec1.asm&quot;&#39;, 13, 10</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;\Flash0\GdtDump\GdtDump.exe&#39;, 13, 10</div></ol></div></div></div></div>Первая строка взята в кавычки, как это делает винда для файлов, у которых в полном пути присутствуют пробелы. Но в принципе это и не важно, шаблон поиска все равно их отбросит: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp;; шаблон для поиска</div><div class="code_line">&nbsp;&nbsp;szPattern &nbsp; &nbsp; db &#39;(\b[a-z]:|\\[a-z0-9]+)\([^/:*?&quot;;;;&#60;&#62;|\r\n]*\)?([^\/:*?&quot;&#60;&#62;|\r\n]*)&#39;, 0</div></ol></div></div></div></div>Выглядит заумно, зато позволяет разбивать любые корректные строки.<br>
Теперь вызываем метод <em class='tag-i'>Execute</em>: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; настраиваем свойства объекта</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetGlobal USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetIgnoreCase USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetMultiline USES ds:eax, ebx, -1</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; задаем шаблон поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szPattern</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD SetPattern USES ds:edx, ebx, eax</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ; подготавливаем строку для поиска</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ANSItoBSTR, offset szFiles</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; сохраняем указатель для SysFreeString</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; вызываем метод Replace</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем место под результат</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD IRegExp2:Execute USES ds:edx, ebx, eax, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ShowMatch</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysFreeString &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; освобождаем BSTR-строку szFiles</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; уничтожаем строку шаблона</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем временный буфер под указатель на строку шаблона</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IRegExp2 ebx METHOD GetPattern USES ds:eax, ebx, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;SysFreeString &nbsp; ; освобождаем память</div></ol></div></div></div></div>Для удобства вся работа с найденными соответствиями вынесена в отдельную подпрограмму - <em class='tag-i'>ShowMatch</em>. Поскольку переменную, под возвращаемое методом <em class='tag-i'>Execute</em> значение, создали на вершине стэка, то она там и останется, как параметр для подпрограммы <em class='tag-i'>ShowMatch</em>, которая в качестве параметра принимает ссылку на экземпляр объекта <em class='tag-i'>IMatchCollection</em>, соответственно эта временная переменная будет удалена со стэка при завершении подпрограммы. Сама подпрограмма состоит из двух вложенных циклов. Внешний цикл проходится по всем объектам <em class='tag-i'>IMatch</em>, то есть по всем соответствиям, а вложенный цикл проходится по всем субсоответствиям, текущего объекта <em class='tag-i'>IMatch</em>: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">proc ShowMatch uses esi edi ebx, @@lpMatchCollection</div><div class="code_line">&nbsp;&nbsp;local @@count, @@index, @@variant:dword:4</div><div class="code_line">&nbsp;&nbsp;local @@firstidx, @@length</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; esi, [@@lpMatchCollection]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; узнаем количество объектов IMatch в коллекции</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем место под результат</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IMatchCollection esi METHOD Count USES ds:edx, esi, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; ecx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ecx - количество найденных совпадений</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;or &nbsp; &nbsp; &nbsp;ecx, ecx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jz &nbsp; &nbsp; &nbsp;@@nofound &nbsp; &nbsp; &nbsp; ; &#60;- ничего не нашли, уходим</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; [@@count], ecx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; [@@index], 0 &nbsp; &nbsp;; индекс текущего объекта IMatch2</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; цикл по всем найденным соответствиям</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@loop:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; получаем ссылку на очередной объект IMatch</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем место под результат</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IMatchCollection esi METHOD Item USES ds:eax, esi, [@@index], esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; edi, [esp] &nbsp; &nbsp; &nbsp;; edi - экземпляр объекта IMatch</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; узнаем значения полей FirstIndex и Length</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lea &nbsp; &nbsp; edx, [@@firstidx]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IMatch edi METHOD FirstIndex USES ds:eax, edi, edx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lea &nbsp; &nbsp; edx, [@@length]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IMatch edi METHOD Length USES ds:eax, edi, edx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; получаем ссылку на строку соответствия</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IMatch edi METHOD Value USES ds:eax, edi, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;BSTRtoANSI</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; выводим на экран данные о найденном соответствии</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_printf &#60;&quot;Match[%i]: %s&quot;,13,10,&quot; First index: %i&quot;,13,10,&quot; Length: %i&quot;,13,10&#62;, [@@index],eax,[@@fidx],[@@len]</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; теперь можно получить субсоответствия, для чего получаем ссылку на ISubMatches</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; для версии 1.0 этот код нужно закомментировать, до метки @@next!</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; выделяем место под результат</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;IMatch2 edi METHOD SubMatches USES ds:eax, edi, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; edi, [esp] &nbsp; &nbsp; &nbsp;; edi - экземпляр объекта ISubMatches</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ISubMatches edi METHOD Count USES ds:eax, edi, esp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; ebx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ebx - количество элементов в ISubMatches</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;; цикл по всем субсоответствиям очередного объекта IMatch</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@subloop:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dec &nbsp; &nbsp; ebx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;js &nbsp; &nbsp; &nbsp;@@next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lea &nbsp; &nbsp; eax, [@@variant]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;ISubMatches edi METHOD Item USES ds:edx, edi, ebx, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;BSTRtoANSI, [dword @@variant+2*4]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_printf &#60;&quot; &nbsp;Sub matches [%i]: %s&quot;,13,10&#62;, ebx, eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jmp &nbsp; &nbsp; @@subloop</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@next: &nbsp; &nbsp; ; переход к следующему IMatch</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;inc &nbsp; &nbsp; [@@index]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dec &nbsp; &nbsp; [@@count]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;jnz &nbsp; &nbsp; @@loop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_printf &#39;-------------------&#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ret</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;@@nofound:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_printf &#39;no matches found!&#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ret</div><div class="code_line">endp</div></ol></div></div></div></div>То есть данная подпрограмма просто выводит на экран все соответствия и их субсоответствия, содержащиеся в переданной ей ссылке на коллекцию <em class='tag-i'>IMatchCollection</em>, в таком виде: <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Match[0]: E:\Program Files\Tasm\Project\RegExpr\exec1.asm</div><div class="code_line">&nbsp;First index: 1</div><div class="code_line">&nbsp;Length: 47</div><div class="code_line">&nbsp;&nbsp;Sub matches [2]: exec1.asm</div><div class="code_line">&nbsp;&nbsp;Sub matches [1]: Program Files\Tasm\Project\RegExpr\</div><div class="code_line">&nbsp;&nbsp;Sub matches [0]: E:</div><div class="code_line">Match[1]: \Flash0\GdtDump\GdtDump.exe</div><div class="code_line">&nbsp;First index: 51</div><div class="code_line">&nbsp;Length: 28</div><div class="code_line">&nbsp;&nbsp;Sub matches [2]: GdtDump.exe</div><div class="code_line">&nbsp;&nbsp;Sub matches [1]: GdtDump\</div><div class="code_line">&nbsp;&nbsp;Sub matches [0]: \Flash0</div></ol></div></div></div></div>И еще. Не трудно заметить, что при получении ссылок на объекты <em class='tag-i'>IMatchCollection</em>, <em class='tag-i'>IMatch</em> и <em class='tag-i'>ISubMatch</em> я не производил никаких проверок на их корректность, эксперименты показали, что эти ссылки всегда корректны. Даже в случае отсутствия соответствий всегда получим указатель на <em class='tag-i'>IMatchCollection</em>, просто его метод <em class='tag-i'>Count</em> вернет ноль. Если соответствия есть, но не найдено ни одного субсоответствия, то все равно получим корректный указатель на <em class='tag-i'>ISubMatches</em>.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Заключение.</strong></span></span></div><br>
Все необходимые сорсы, инклюды и либы в аттаче. Для компиляции всех примеров достаточно запустить makeall.bat, предварительно поместив в папку компилятор tasm32 и линковщик tlink32, или аналогичные, подправив батник.]]></description>
        <author>AndNot</author>
        <category>Assembler FAQ</category>
      </item>
	
      </channel>
      </rss>
	