# -*- coding: UTF-8 -*- ## ## ## ##html2code.html ## ## ## ## ## ## ##

html2code.html

## ##

Процедура html2code() - это простой конвертер, способный преобразовывать html-страницы, содержащие код Python, в "чистые" (без тегов html и объяснительного текста) сценарии Python с расширением .py и запускать их на выполнение. Фактически, это фильтр, отбрасывающий все, что не находится между тегами <CODE>…</CODE>. А между ними как раз и находятся "кусочки" кода Python. В результате в выходной файл записывается "голый" сценарий Python, "склеенный" из этих кусочков.

## ##Процедура html2code() написана на Python 2. Для ее работы требуется дополнительный модуль code_tag.py. ## ##html-файлы со встроенными сценариями Python должны быть оформлены по особым правилам.

## ##Есть четыре варианта запуска процедуры html2code():
## ##
##
html2code('',0,0)
холостой запуск: скрипт Python не создается, и код не запускается на выполнение
##
html2code('',0,1)
сценарий Python не создается, но код запускается на выполнение
##
html2code('',1,0)
генерируется скрипт Python, но код на выполнение не запускается
##
html2code('',1,1)
сценарий Python создается и запускается на выполнение
##
## ##Процедура может использоваться в интерактивном режиме, когда пользователь сам находит нужный скрипт (в html-формате) в открывшемся диалоговом окне и запускает его на выполнение без создания промежуточного файла с расширением .py.

## ##С другой стороны, процедура html2code может вызываться из других сценариев Python. В последнем случае имя html-файла с кодом задается через первый параметр этой процедуры.

## ##Третий вариант - импортирование модуля, оформленного в виде html-файла. Тогда перед командой import имя_модуля в сценарии, использующем такой модуль, нужно вызвать процедуру с параметрами: html2code('имя_модуля',1,0).

## ## ## ##

Используемые модули

## ##Код модуля code_tag.py (не является частью этого файла): ## ##

##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. Использовать их в явном виде, равно как заменить угловые скобки на символы &lt; и &gt; нельзя: программа будет работать неправильно.
## ## ##

# -*- coding: UTF-8 -*-
# Этот код получен из файла html2py.html с помощью утилиты html2py.py
import code_tag
from Tkinter import *
import tkFileDialog
import tkMessageBox
import os
import StringIO
##
## ## ##

Функция choice()

## ##Функция choice выводит на экран стандартное окна выбора файла и возвращает имя файла, выбранного пользователем. Команда root.withdraw() убирает с экрана пустое окно Tk.

## ##В файле html2code.ini хранится имя последнего сконвертированного и записанного на диск файла; окно выбора файла открывается именно в каталоге этого файла. Если файл html2code.ini по какой-то причине не удается открыть, выбор файла производится из рабочего каталога программы.

## ##Переменная ifile содержит имя файла с расширением *.py, который в последний раз был сохранен утилитой html2code. При каждом сохранении сконвертированного в сценарий Python файла его имя записывается в служебный файл html2code.ini.

## ##Параметр initialdir - название каталога, в котором открывается диалоговое окно; оно соответствует последнему записанному на диск сценарию, обработанному утилитой html2code.py. Функция os.path.split() возвращает кортеж строк, содержащих адрес каталога и имя файла.
## ## ##


def choice():
    root=Tk()
    root.withdraw()
    try:
        filedd=open("html2code.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
##
## ## ##

Процедура html2code(html_name,file_py,run)

## ##Главная процедура html2code получает три входных параметра, определяющих ее дальнейшие действия. Причем file_py!=0 говорит, что будет создан файл с расширением .py; run!=0 означает, что сгенерированный скрипт будет запущен на выполнение. html_name - это имя входного файла, которое может быть задано явно, как параметр html2code. В этом случае окно выбора файла не выводится.

## ##a - временный файл, куда записывается код Python, заключенный между тегами <CODE> и </CODE> который в конце будет записан в итоговый файл.

## ##Переключатель switch включает вывод текстовой информации во временный файл a. Пока не появится первый тег <CODE>, ничего выводиться не будет.

## ##

  
def html2code(html_name,file_py,run):
    global switch
    switch=0
    a = StringIO.StringIO()

    if html_name=='':
        b=open(choice().show(), 'r')
    else:
        b=open(html_name,'r')
##
## ## ##Далее считываем выбранный файл в переменную b1 и будем побайтно перебирать его содержимое в поисках тегов <CODE> и </CODE>. Вспомогательной переменной pause присваиваем значение, заведомо большее длины файла. Условия i<(len(b1)-5) и i<(len(b1)-6) нужны, чтобы при проверке мы не вылезали за конец файла. Числа 5 и 6 здесь соответствуют длине строк '<CODE>' и '</CODE>' (+1). Когда обнаруживается тег <CODE>, переключателю switch присваивается ненулевое значение, и через 6 шагов цикла (pause=i+5; чтобы не выводились символы '<code>' или '<CODE>') начинается вывод кода Python. Итак, если мы миновали тег <CODE> (switch==1) и после него прошло нужное количество шагов, чтобы не выводился сам тег (pause-i<0), рассматриваемый байт записывается во временный файл a.

## ##ВАЖНО: условие 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, и заменить угловые скобки на их символические обозначения (&lt; и &gt;) нельзя. Поэтому код Python, где явно присутствуют сочетания символов <CODE> и </CODE>, необходимо вынести за пределы этого файла, в отдельный модуль code_tag.py.
## ##

    
    b1=b.read()
    i=0
    pause=len(b1)+10
    
    for i in range(len(b1)):
        if (i<(len(b1)-5)):
            start_tag=b1[i]+b1[i+1]+b1[i+2]+b1[i+3]+b1[i+4]+b1[i+5]
            if (start_tag==code_tag.code_start1()) | (start_tag==code_tag.code_start2()):
                switch=1
                pause=i+5
        if (i<(len(b1)-6)):
            end_tag=b1[i]+b1[i+1]+b1[i+2]+b1[i+3]+b1[i+4]+b1[i+5]+b1[i+6]
            if (end_tag==code_tag.code_end1()) | (end_tag==code_tag.code_end2()):
                switch=0
        if (switch==1)&(pause-i<0):
            a.write(b1[i])##
## ##В переменной 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("html2code.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("html2code.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__':
    html2code('',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 ## ##
## ##