Процедура html2py() - это простой конвертер, способный преобразовывать html-страницы, содержащие код Python, в сценарии Python с расширением .py и запускать их на выполнение. Фактически, это фильтр, превращающий все, что не находится между тегами <CODE>…</CODE>, в комментарии Python. Между этими тегами находятся "кусочки" кода Python. В целом они представляют собой законченную программу на Python, ее можно редактировать и сохранять в обычном редакторе, например в IDLE. Возможно и обратное преобразование: другая процедура py2html() убирает все добавленные комментарии, восстанавливая оформление исходного html-файла.
Процедуры html2py() и py2html() написаны на Python 2. Для их работы нужен дополнительный модуль code_tag.py. html-файлы со встроенными сценариями Python должны быть оформлены по особым правилам. Есть четыре варианта запуска процедуры html2py():С другой стороны, процедура html2py может вызываться из других сценариев Python. В последнем случае имя html-файла с кодом задается через первый параметр этой процедуры.
Третий вариант - импортирование модуля, оформленного в виде html-файла. Тогда перед командой import имя_модуля в сценарии, использующем такой модуль, нужно вызвать процедуру с параметрами: html2py('имя_модуля',1,0).
def code_start1(): return '<CODE>' def code_start2(): return '<code>' def code_end1(): return '</CODE>' def code_end2(): return '</code>'В модуле code_tag.py хранятся сочетания символов '<CODE>', '<code>', '</CODE>' и '</code>'. В данном файле они - часть кода Python. Использовать их в явном виде, равно как заменить угловые скобки на символы < и > нельзя: программа будет работать неправильно.
# -*- coding: UTF-8 -*-
# Этот код получен из файла html2py.html с помощью утилиты html2py.py
import code_tag
from Tkinter import *
import tkFileDialog
import tkMessageBox
import os
import StringIO
В файле html2py.ini хранится имя последнего сконвертированного и записанного на диск файла; окно выбора файла открывается именно в каталоге этого файла. Если файл html2py.ini по какой-то причине не удается открыть, выбор файла производится из рабочего каталога программы.
Переменная ifile содержит имя файла с расширением *.py, который в последний раз был сохранен утилитой html2py. При каждом сохранении сконвертированного в сценарий Python файла его имя записывается в служебный файл html2py.ini.
Параметр initialdir - название каталога, в котором открывается диалоговое окно; оно соответствует последнему записанному на диск сценарию, обработанному утилитой html2py.py. Функция os.path.split() возвращает кортеж строк, содержащих адрес каталога и имя файла.
def choice():
root=Tk()
root.withdraw()
try:
filedd=open("html2py.ini", "r")
ifile=filedd.readline()
filedd.close()
except IOError:
ifile=""
myfiletypes=[('HTML-файлы', '*.html'),('Все файлы', '*')]
filetext=tkFileDialog.Open(title='Запуск...',initialdir=os.path.split(ifile)[0],filetypes=myfiletypes)
return filetext
a - временный файл, куда записывается код Python, заключенный между тегами <CODE> и </CODE> который в конце будет записан в итоговый файл.
Переключатель switch включает вывод текстовой информации во временный файл a. Пока не появится первый тег <CODE>, ничего выводиться не будет.
def html2py(html_name,file_py,run):
global code
code=0
a = StringIO.StringIO()
if html_name=='':
b=open(choice().show(), 'r')
else:
b=open(html_name,'r')
Считываем открытый файл по одной строке и суммируем эти строки в переменной b1. Начальное значение b1 не пустая строка, как можно было бы подумать, а '# -*- coding: UTF-8 -*-\n'. Это связано с тем, что для подключения поддержки русского языка эта строка в Python-программе должна быть самой первой. Поэтому при конвертации html-файла она каждый раз принудительно вставляется в начало генерируемого сценария Python. Обратная процедура py2html.py, в свою очередь, принудительно ее убирает.
b1='# -*- coding: UTF-8 -*-\n'
Переменная цикла line по очереди ссылается на все строки считываемого файла. Мы будем побайтно перебирать каждую из них в поисках тегов <CODE> и </CODE>. Условия i<(len(b1)-5) и i<(len(b1)-6) нужны, чтобы при проверке мы не вылезали за конец строки. Числа 5 и 6 здесь соответствуют длине строк '<CODE>' и '</CODE>' (+1). Переменная start_tag представляет собой что-то вроде окошечка (см. рисунок), которое посимвольно перемещается по строке слева направо, пока в окошечко не попадет сочетание символов <CODE>. Тогда переключателю code присваивается ненулевое значение (область кода Python), а метке code_start - значение, равное 1 (в строке обнаружен стартовый тег <CODE>).Затем в том же шаге цикла проводится аналогичный поиск тега </CODE>. Причем, если он обнаруживается, то не только меняются значения переменных code и code_end, но и перед самим этим тегом ставится значок "##", превращающий оставшуюся часть строки в комментарий. Строка line разбивается на две части методом split(); границей раздела является комбинация символов </CODE>. После этого обязательно нужен оператор break, принудительно прекращающий поиск тегов в строке, так как строка из-за вставки удлиняется, и тот же самый тег будет находиться несколько раз.
Условие if (start_tag==code_tag.code_start1()) | (start_tag==code_tag.code_start2()): идентично условию if (start_tag=='<CODE>') | (start_tag=='<code>'): и if (end_tag==code_tag.code_end1()) | (end_tag==code_tag.code_end2()): идентично if (end_tag=='</CODE>') | (end_tag=='</code>'):. Здесь теги <CODE> и </CODE> - часть кода Python, и заменить угловые скобки на их символические обозначения (< и >) нельзя. Поэтому код Python, где явно присутствуют сочетания символов <CODE> и </CODE>, вынесен за пределы этого файла в отдельный модуль code_tag.py.
for line in b.readlines():
code_start=0
code_end=0
for i in range(len(line)):
if (i<(len(line)-5)):
start_tag=line[i]+line[i+1]+line[i+2]+line[i+3]+line[i+4]+line[i+5]
if (start_tag==code_tag.code_start1()) | (start_tag==code_tag.code_start2()):
code=1
code_start=1
if (i<(len(line)-6)):
end_tag=line[i]+line[i+1]+line[i+2]+line[i+3]+line[i+4]+line[i+5]+line[i+6]
if (end_tag==code_tag.code_end1()) | (end_tag==code_tag.code_end2()):
code=0
code_end=1
line_split=line.split(line[i]+line[i+1]+line[i+2]+line[i+3]+line[i+4]+line[i+5]+line[i+6])
line=line_split[0]+'##'+code_tag.code_end1()+line_split[1]
break
В зависимости от результатов поиска тегов <CODE> и </CODE> рассматриваемая строка или приплюсовывается к строке b1 без изменений, или, если в строке есть тег <CODE>, она превращается в комментарий (в ее начало вставляются символы "##"). После того как цикл обработал все строки файла, итоговая строковая переменная b1 записывается во временный файл a.
if (code_end==0):
if (code==0) ^ (code_start==1):
line='##'+line
b1=b1+line
a.write(b1)
В переменной dir_file хранится имя директории, в которой находится обрабатываемый html-файл и куда будет записан сгенерированный из него сценарий Python.
Если файл с расширением .py создавать нужно (if file_py!=0:), то, прежде всего нужно заменить расширение исходного файла с .html на .py. Новое имя файла определяется выражением file_title[0]+'/'+name_py[0]+'.py'. Если файл с таким названием уже существует, то надо спросить, перезаписывать его или нет, с помощью функции tkMessageBox.askquestion().
dir_file=os.path.split(b.name)[0]
if file_py!=0:
file_title=os.path.split(b.name)
name_py=file_title[1].split(".")
if os.path.isfile(file_title[0]+'/'+name_py[0]+'.py')!=0:
if tkMessageBox.askquestion("Сохранить как",\
file_title[0]+'/'+name_py[0]+'.py'+ u' уже существует. Заменить?')=="yes":
Получить содержимое извлеченного из html-файла сценария Python можно с помощью команды a.getvalue(). Кроме перезаписи существующего сценария Python нужно еще записать название обрабатываемого html-файла во вспомогательный ini-файл. Затем уточняем: на самом ли деле нужно запускать скрипт (if run!=0:), и если да, то запускаем его с помощью функции exec().
ini_file=open("html2py.ini","w")
ini_file.write(b.name)
ini_file.close()
open(file_title[0]+'/'+name_py[0]+'.py','w').write(a.getvalue())
if run!=0:
filew=open(file_title[0]+'/'+name_py[0]+'.py', "r")
exec(filew)
filew.close()
else:
pass
else:
pass
Если файла с таким именем нет, создаем его без лишних вопросов, не забывая прежде записать его имя во вспомогательный ini-файл. Если скрипт нужно запустить (if run!=0:), запускаем его с помощью функции exec()
else:
ini_file=open("html2py.ini","w")
ini_file.write(b.name)
ini_file.close()
open(file_title[0]+'/'+name_py[0]+'.py','w').write(a.getvalue())
if run!=0:
filew=open(file_title[0]+'/'+name_py[0]+'.py', "r")
exec(filew)
filew.close()
else:
pass
Если файл с расширением .py создавать не требуется, уточняем, на самом ли деле нужно запускать полученный скрипт (if run!=0:). Если да, то вместо обычного файла на выполнение запускаем наш временный файл a, который исчезнет после завершения работы программы.
else:
if run!=0:
exec(a.getvalue())
else:
pass
a.close()
if __name__ == '__main__':
html2py('',1,0)
Данный html-файл содержит в себе сценарий Python, который может быть извлечен и/или запущен на выполнение с помощью утилиты html2py.py.
Автор: Филипп Занько
Web-адрес: http://www.russianlutheran.org/python/python.html
Лицензия: Creative Commons Attribution-ShareAlike 3.0 Unported License
О своих предложениях, замеченных ошибках, неточностях, опечатках просьба сообщать по электронному адресу:
russianlutheran@gmail.com