Кто работал со строками на ассемблере, тот меня поймёт
Парсинг или обработка строк на этом языке пожалуй самая больная тема при написании проектов серьёзнее "Hello World". Ну можно с этим смириться, когда в коде необходимо это сделать пару тройку раз, а когда больше? И без того трудночитаемый ассемблерный код превращается просто в кашу.
Вы скажете, а зачем писать крупные проекты на ассемблере? Мы не будем выяснять ответ на этот вопрос, точно так же как не будем выяснять а нужно ли то, что я опишу ниже. Тот, кто с этим столкнётся или уже сталкивался - меня поймут, остальные могут прочесть просто для расширения кругозора
Люди, которые программируют на ЯВУ имеют возможность использовать очень мощный инструмент для работы со строками - регулярные выражения. Мало, кто с этим знаком, но поверьте регулярные выражения лучшее средство в работе со строковыми данными. Убедитесь в этом ниже. Тот, кто не знаком с регулярками я могу посоветовать книгу:
Фридл Дж. Регулярные выражения (2-е изд.), Питер 2003, 464 с. Её можно скачать и в электронном виде из сети. Прочтите хотя бы первые страниц 100, этого будет достаточно для составления простеньких выражений.
Итак, если я пишу на ВБ я использую интерфейс vbscript.dll, там хороший движок, но увы номеров COM интерфейсов я так и не нашёл. На С++ тоже есть движки, но я ниразу с выражениями на этом языке не работал(а кто работал можете собрать lib'y на каком-нибудь движке и выслать мне, буду благодарен). Ну что, остаётся делфи, там есть отличный компонент - TRegExpr. Но делфи компилирует файлы в формат OMF, а чтобы собрать либу и потом подключать её к своему проекту на ассемблере нам нужен формат COFF, конвертёров нет. Остаётся одно: писать dll с экспортируемой функцией. Что я и сделал, прототип функции следующий:
Expressions - само выражение.
lpData - указатель на данные, которые следует обработать.
NextFlag - у компонента TRegExpr есть метод ExecNext, который ищет следующее вхождение в данных. Так вот, этот флаг говорит о том надо ли его использовать, если не надо то мы просто проверим данные на хотя бы одно совпадение. Дальше поймёте
Splitter - Указатель на разделитель. Если флаг NextFlag установлен, то при выборке всех совпадений из даных они будут разделены между собой этой строкой.
Чтобы подключить dll к программе делаем так:
Саму regexp.dll вы можете найти в приложении к статье.
Далее я объясню как работает функция Exec без флага NextFlag. Если NextFlag=0, то параметр Splitter тоже можно передавать как NULL, обязательными являются только первые два параметра, давайте их определим:
Допустим нам надо проверить является введённая строка шестнадцатиричным числом в сиподобном формате. Можете себе представить сколько бы это усилий заняло если бы вы использовали только ассемблер. А так мы объявляем простое выражение: 0x[a-fA-F0-9]+, которое можно разбить на три логических лексемы, если не считать символов ^ и $, они обозначают соответственно начало и конец строки:
0x - говорит о том, что первыми двумя символами в строке должны быть именно эти.
[a-fA-F0-9] - это называется символьный класс. В данном случае он означает, что в строке могут быть только следующие символы: 1234567890ABCDEFabcdef.
+ - этот метасимвол говорит о том, что таких символьных классов у нас может быть 1 и более.
Ну lpData - соответственно данные которые нужно проверить на соответствие выражению Expressions.
Ну что, вызываем функцию:
Запускаем программу и видим сообщение True! Работает Ради интереса измените lpData таким образом, чтобы он не соответствовал формату, ессно при этом сообщение вам лицезреть не придётся
Теперь ещё более полезная функция. Допустим имеются у нас такие данные:
lpData db "Мой почтовый ящик vasya_pupkin@mail.ru, но вы можете писать на pupkin_vasya@gmail.com",0
Нам нужно из этой строки выредгнуть все почтовые адреса и представить их в таком виде:
mail
mail
Нет ничего проще! Составляем выражение:
Сложновато? Знаю Но зато какой результат! В качестве разделителя у нас перенос строки, значит определяем параметр Splitter для функции Exec следующим образом:
Splitter db 13,10,0
И вызываем:
После вызова в eax будет указатель на "отсеянные" данные:
Как результат видим такое сообщение:
А теперь представьте сколько бы понадобилось сил, чтобы реализовать это на ассемблере
В качестве приложения в статье я даю regexp.dll и пример использования.
Приложение
BUG(O)R
http://hunger.ru
ICQ:827887
Источник: http://hunger.ru
Парсинг или обработка строк на этом языке пожалуй самая больная тема при написании проектов серьёзнее "Hello World". Ну можно с этим смириться, когда в коде необходимо это сделать пару тройку раз, а когда больше? И без того трудночитаемый ассемблерный код превращается просто в кашу.
Вы скажете, а зачем писать крупные проекты на ассемблере? Мы не будем выяснять ответ на этот вопрос, точно так же как не будем выяснять а нужно ли то, что я опишу ниже. Тот, кто с этим столкнётся или уже сталкивался - меня поймут, остальные могут прочесть просто для расширения кругозора
Люди, которые программируют на ЯВУ имеют возможность использовать очень мощный инструмент для работы со строками - регулярные выражения. Мало, кто с этим знаком, но поверьте регулярные выражения лучшее средство в работе со строковыми данными. Убедитесь в этом ниже. Тот, кто не знаком с регулярками я могу посоветовать книгу:
Фридл Дж. Регулярные выражения (2-е изд.), Питер 2003, 464 с. Её можно скачать и в электронном виде из сети. Прочтите хотя бы первые страниц 100, этого будет достаточно для составления простеньких выражений.
Итак, если я пишу на ВБ я использую интерфейс vbscript.dll, там хороший движок, но увы номеров COM интерфейсов я так и не нашёл. На С++ тоже есть движки, но я ниразу с выражениями на этом языке не работал(а кто работал можете собрать lib'y на каком-нибудь движке и выслать мне, буду благодарен). Ну что, остаётся делфи, там есть отличный компонент - TRegExpr. Но делфи компилирует файлы в формат OMF, а чтобы собрать либу и потом подключать её к своему проекту на ассемблере нам нужен формат COFF, конвертёров нет. Остаётся одно: писать dll с экспортируемой функцией. Что я и сделал, прототип функции следующий:
Код:
function Exec(Expessions: pChar; lpData: pChar; NextFlag: boolean; Splitter: pChar): dword; stdcall;
Expressions - само выражение.
lpData - указатель на данные, которые следует обработать.
NextFlag - у компонента TRegExpr есть метод ExecNext, который ищет следующее вхождение в данных. Так вот, этот флаг говорит о том надо ли его использовать, если не надо то мы просто проверим данные на хотя бы одно совпадение. Дальше поймёте
Splitter - Указатель на разделитель. Если флаг NextFlag установлен, то при выборке всех совпадений из даных они будут разделены между собой этой строкой.
Чтобы подключить dll к программе делаем так:
Код:
.data?
lpExec dd ?
.code
start:
invoke LoadLibrary, $CT0("regexp.dll")
invoke GetProcAddress, eax, $CT0("Exec")
mov lpExec,eax
Саму regexp.dll вы можете найти в приложении к статье.
Далее я объясню как работает функция Exec без флага NextFlag. Если NextFlag=0, то параметр Splitter тоже можно передавать как NULL, обязательными являются только первые два параметра, давайте их определим:
Код:
.data
Expressions db "^0x[a-fA-F0-9]+$",0
lpData db "0xFFFF1111",0
Допустим нам надо проверить является введённая строка шестнадцатиричным числом в сиподобном формате. Можете себе представить сколько бы это усилий заняло если бы вы использовали только ассемблер. А так мы объявляем простое выражение: 0x[a-fA-F0-9]+, которое можно разбить на три логических лексемы, если не считать символов ^ и $, они обозначают соответственно начало и конец строки:
0x - говорит о том, что первыми двумя символами в строке должны быть именно эти.
[a-fA-F0-9] - это называется символьный класс. В данном случае он означает, что в строке могут быть только следующие символы: 1234567890ABCDEFabcdef.
+ - этот метасимвол говорит о том, что таких символьных классов у нас может быть 1 и более.
Ну lpData - соответственно данные которые нужно проверить на соответствие выражению Expressions.
Ну что, вызываем функцию:
Код:
push 0
push 0
push offset lpData
push offset Expressions
call lpExec
test eax,eax
je @f
invoke MessageBox, 0, $CT0("True"), $CT0("Msg"),MB_OK+MB_ICONINFORMATION
@@:
Call ExitProcess
Запускаем программу и видим сообщение True! Работает Ради интереса измените lpData таким образом, чтобы он не соответствовал формату, ессно при этом сообщение вам лицезреть не придётся
Теперь ещё более полезная функция. Допустим имеются у нас такие данные:
lpData db "Мой почтовый ящик vasya_pupkin@mail.ru, но вы можете писать на pupkin_vasya@gmail.com",0
Нам нужно из этой строки выредгнуть все почтовые адреса и представить их в таком виде:
Нет ничего проще! Составляем выражение:
Код:
Expressions db "[_a-zA-Z\d\-\.]+@[_a-zA-Z\d\-]+(\.[_a-zA-Z\d\-]+)+",0
Сложновато? Знаю Но зато какой результат! В качестве разделителя у нас перенос строки, значит определяем параметр Splitter для функции Exec следующим образом:
Splitter db 13,10,0
И вызываем:
Код:
push offset Splitter
push 1
push offset lpData
push offset Expressions
call lpExec
После вызова в eax будет указатель на "отсеянные" данные:
Код:
test eax,eax
je @f
invoke MessageBox, 0, eax, $CT0("Msg"),MB_OK+MB_ICONINFORMATION
@@:
Call ExitProcess
Как результат видим такое сообщение:
---------------------------
Msg
---------------------------
vasya_pupkin@mail.ru
pupkin_vasya@gmail.com
---------------------------
ОК
---------------------------
А теперь представьте сколько бы понадобилось сил, чтобы реализовать это на ассемблере
В качестве приложения в статье я даю regexp.dll и пример использования.
Приложение
BUG(O)R
http://hunger.ru
ICQ:827887
Источник: http://hunger.ru