Иногда наступают моменты, когда обычного wcmatchдля поиска совпадений уже недостаточно, а использовать новые средства разработки нельзя/затратно/нет знаний (нужное подчеркнуть). Так как я более 3-х лет в свободное время увлекаюсь программированием под Linux, то уже не представляю поиск по строкам без регулярных выражений. Но, раз основная работа связана с AutoCAD и AutoLISP, приходится искать другие инструменты решения задач.
В случае с регулярными выражениями на помощь приходит объект VBScript.RegExp, являющийся стандартным объектом VBScript 5 (%windir%\system32\vbscript.dll).
Что такое регулярные выражения, читаем здесь.
Описания и примеры VBScript.RegExp на VBScript можно почитать здесь.
Если интерес не пропал, смотрим, как это все дело прикрутить к AutoLISPу.
Для начала напишем функцию, регистрирующую объект VBScript.RegExp и возвращающего ссылку на него.
Теперь, когда у нас есть ссылка на объект можно приступать к созданию оберток к его методам:
Объект VBScript.Regexp содержит следующие методы:
Test - Сравнение текста с заданным шаблоном
Replace - Замена подстроки, соответствующей шаблону
Execute - Извлечение текста, заданного шаблоном
И свойства этого объекта:
Global - Проверка по всему тексту (True) или до первого соответствия (False)
IgnoreCase - Игнорировать регистр (True) или учитывать (False)
Pattern - Шаблон искомой подстроки (собственно регулярное выражение)
Multiline - Многострочный (True) или однострочный объект (False)
Мне потребовались 3 функции-обертки, приведу их ниже:
Сравнение текста с шаблоном (результат - T или nil):
Ну и пара примеров как итог:
В случае с регулярными выражениями на помощь приходит объект VBScript.RegExp, являющийся стандартным объектом VBScript 5 (%windir%\system32\vbscript.dll).
Что такое регулярные выражения, читаем здесь.
Описания и примеры VBScript.RegExp на VBScript можно почитать здесь.
Если интерес не пропал, смотрим, как это все дело прикрутить к AutoLISPу.
Для начала напишем функцию, регистрирующую объект VBScript.RegExp и возвращающего ссылку на него.
;;; <LISPDOC> ;;; <SUBR>(regexp-regapp)</SUBR> ;;; <DESC>Get VBScript.RegExp pointer</DESC> ;;; <RET>VBScript.RegExp pointer</RET> ;;; </LISPDOC> (defun regexp-regapp (/) (vla-getinterfaceobject (vlax-get-acad-object) "VBScript.RegExp"))
Теперь, когда у нас есть ссылка на объект можно приступать к созданию оберток к его методам:
Объект VBScript.Regexp содержит следующие методы:
Test - Сравнение текста с заданным шаблоном
Replace - Замена подстроки, соответствующей шаблону
Execute - Извлечение текста, заданного шаблоном
И свойства этого объекта:
Global - Проверка по всему тексту (True) или до первого соответствия (False)
IgnoreCase - Игнорировать регистр (True) или учитывать (False)
Pattern - Шаблон искомой подстроки (собственно регулярное выражение)
Multiline - Многострочный (True) или однострочный объект (False)
Мне потребовались 3 функции-обертки, приведу их ниже:
Сравнение текста с шаблоном (результат - T или nil):
;;; <LISPDOC>
;;; <SUBR>(regexp-match regexp_object pattern test_string is_global case_sensitive)</SUBR>
;;; <DESC>Test string match with Regexp</DESC>
;;; <ARG>regexp_object - VBScript.RegExp pointer</ARG>
;;; <ARG>pattern - regexp pattern</ARG>
;;; <ARG>test_string - string to test</ARG>
;;; <ARG>is_global - global match key (g)</ARG>
;;; <ARG>case_sensitive - case sensitive key (i)</ARG>
;;; <RET>T if matches \ nil otherwise</RET>
;;; </LISPDOC>
(defun regexp-match (regexp_object pattern test_string is_global case_sensitive / result)
(if regexp_object
(progn
(vlax-put regexp_object 'Pattern pattern)
(vlax-put regexp_object 'Global (if is_global acTrue acFalse))
(vlax-put regexp_object 'IgnoreCase (if case_sensitive acFalse acTrue))
(setq result (vlax-invoke regexp_object 'Test test_string))
(vlax-put regexp_object 'Pattern "")))
(if (and result (/= result 0))
T
nil))
Замена подстроки (результат - новая строка):;;; <LISPDOC>
;;; <SUBR>(regexp-replace regexp_object pattern replace_string test_string is_global case_sensitive)</SUBR>
;;; <DESC>Replace Regexp pattern with string</DESC>
;;; <ARG>regexp_object - VBScript.RegExp pointer</ARG>
;;; <ARG>pattern - regexp pattern</ARG>
;;; <ARG>replace_string - string replacement</ARG>
;;; <ARG>test_string - string to test</ARG>
;;; <ARG>is_global - global match key (g)</ARG>
;;; <ARG>case_sensitive - case sensitive key (i)</ARG>
;;; <RET>String after replace</RET>
;;; </LISPDOC>
(defun regexp-replace (regexp_object pattern replace_string test_string is_global case_sensitive / result)
(if regexp_object
(progn
(vlax-put regexp_object 'Pattern pattern)
(vlax-put regexp_object 'Global (if is_global acTrue acFalse))
(vlax-put regexp_object 'IgnoreCase (if case_sensitive acFalse acTrue))
(setq result (vlax-invoke regexp_object 'Replace test_string replace_string))
(vlax-put regexp_object 'Pattern "")))
result)
Извлечение текста по шаблону (результат - список элементов '(("Значение" Индекс Длина)));;; <LISPDOC>
;;; <SUBR>(regexp-execute regexp_object pattern test_string is_global case_sensitive)</SUBR>
;;; <DESC>Execute regexp and return collection of found strings</DESC>
;;; <ARG>regexp_object - VBScript.RegExp pointer</ARG>
;;; <ARG>pattern - regexp pattern</ARG>
;;; <ARG>test_string - string to test</ARG>
;;; <ARG>is_global - global match key (g)</ARG>
;;; <ARG>case_sensitive - case sensitive key (i)</ARG>
;;; <RET>List of found strings ((String Index Length)...)</RET>
;;; </LISPDOC>
(defun regexp-execute (regexp_object pattern test_string is_global case_sensitive / result collection)
(if regexp_object
(progn
(vlax-put regexp_object 'Pattern pattern)
(vlax-put regexp_object 'Global (if is_global acTrue acFalse))
(vlax-put regexp_object 'IgnoreCase (if case_sensitive acFalse acTrue))
(setq collection (vlax-invoke regexp_object 'Execute test_string))
(vlax-put regexp_object 'Pattern "")))
(vlax-for item collection
(setq result
(cons
(list
(vlax-get item 'Value)
(vlax-get item 'FirstIndex)
(vlax-get item 'Length))
result))))
Ну и пара примеров как итог:
_$ (setq reg (regexp-regapp))
_$ (regexp-match reg "\\d{3}-\\d{3}" "Phone: 333-444" T nil)
T
_$ (regexp-replace reg "\\s{2,}" " " "There are a lot of spaces in string" T nil)
"There are a lot of spaces in string"
_$ (regexp-execute reg "\\d{3}-\\d{3}" "Home Number: 333-444; Work Number: 444-333" T nil)
(("444-333" 35 7) ("333-444" 13 7))
Комментариев нет:
Отправить комментарий