Чтение онлайн

ЖАНРЫ

Написание скриптов для Blender 2.49

Anders Michel

Шрифт:

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

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

Регулярные выражения очень мощны и множество программистов любят их универсальность (и множество других ненавидят их ужасную неудобочитаемость). Любите Вы или ненавидите их, они очень выразительные: сопоставление любого десятичного числа можно просто выразить как, например, \d+ (одна или более цифр). Если Вы ищете слово, которое пишется по буквам по-разному в Британском или Американском вариантах английского, как например, colour/color, Вы можете делать сопоставление с любым из них с помощью выражения colou?r (color с необязательным u).

Следующий код покажет, что встроенный редактор Блендера может быть оснащён этим полезным средством поиска просто с помощью нескольких строк кода. Представленный скрипт должен быть установлен в каталоге скриптов Блендера, и его можно будет затем вызывать из меню текстового редактора как Text | Text Plugins | Regular Expression Search, или комбинацией горячих клавиш Alt + Ctrl + R. При этом появится небольшое всплывающее поле ввода, где пользователь может ввести регулярное выражение (там будет запомнено последнее введенное регулярное выражение), и если пользователь щелкнет по кнопке OK или нажмёт Enter, курсор будет установлен в первом из мест, которые соответствуют регулярному выражению, с выделением сопоставленного выражения.

Чтобы зарегистрировать скрипт в качестве текстового плугина с назначенной горячей клавишей, первые строки скрипта состоят из привычных заголовков, дополненных пунктом Shortcut: (выделено ниже):

#!BPY

"""

Name: 'Regular Expression Search'

Blender: 249

Group: 'TextPlugin'

Shortcut: 'Ctrl+Alt+R'

Tooltip: 'Find text matching a regular expression'

"""

Следующим шагом нужно импортировать необходимые модули. Питон предоставляет нам стандартный модуль re, который хорошо документирован (онлайн документации достаточно даже для пользователей-новичков, незнакомых с регулярными выражениями. По-русски почитать можно, например, здесь: http://www.intuit.ru/department/pl/python/6/4.html — прим. пер.), и мы импортируем модуль Блендера bpy. В этой книге мы не часто используем этот модуль, так как он помечен, как экспериментальный, но в этом случае мы нуждаемся в нём, чтобы узнать, какой текстовый буфер является активным:

from Blender import Draw,Text,Registry

import bpy

import re

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

def popup(msg):

Draw.PupMenu(msg+'%t|Ok')

return

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

keyname = 'regex'

Функция run связывает всю функциональность вместе; она извлекает активный текстовый буфер и завершается, если его не нашлось:

def run:

txt = bpy.data.texts.active

if not txt: return

Далее, она извлекает позицию курсора внутри этого буфера:

row,col = txt.getCursorPos

Прежде, чем показать пользователю всплывающее окно для ввода регулярного выражения, мы проверяем, есть ли уже сохраненное ранее выражение в реестре. Мы просто извлекаем его, и если это терпит неудачу, мы ставим выражением по-умолчанию пустую строку (выделено). Заметьте, что мы не передаем никаких дополнительных параметров в функцию GetKey, поскольку мы хотим сохранить любую информацию на диск в этом случае. Если пользователь вводит пустую строку, мы просто делаем возврат без поиска:

d=Registry.GetKey(keyname)

try:

default = d['regex']

except:

default = ''

pattern = Draw.PupStrInput('Regex: ',default,40)

if pattern == None or len(pattern) == 0 : return

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

try:

po = re.compile(pattern)

except:

popup('Illegal expression')

return

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

first = True

for string in txt.asLines(row):

if first :

string = string[col:]

mo = re.search(po,string)

Если есть сопоставление, мы отмечаем его начало в пределах строки и его длину (должным образом исправленную, если это строка первая) и устанавливаем позицию курсора на текущую строку и в начало сопоставления (выделено). Мы также устанавливаем "позицию выделения" в позицию сопоставления плюс длина сопоставления, таким образом наше сопоставление будет выделено, и затем делаем возврат. Если нет сопоставления в пределах строки, мы увеличиваем индекс строки row и продолжаем цикл.

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

if mo != None :

i = mo.start

l = mo.end-i

if first :

i += col

txt.setCursorPos(row,i)

txt.setSelectPos(row,i+l)

break

row += 1

first = False

else :

popup('No match')

Registry.SetKey(keyname,{'regex':pattern})

if __name__ == '__main__':

run

Полный код доступен как regex.py в файле regex.blend, но может быть размещён в каталоге скриптов Блендер с подходящим именем, как например, textplugin_regex.py.

Поделиться с друзьями: