Страница 1 из 13
Скрипты для Demagog
Добавлено: 16 окт 2018 13:38
flegont
Demagog умеет выполнять вычисления по заранее заданным в текстовом файле командам. Такой текст, содержащий только команды и комментарии к ним, называется
скрипт. Для выполнения скриптов в Demagog'e используется встроенный интерпретатор языка программирования
Lua (версии 5.3).
Файлы скриптов должны иметь расширение .lua
Чтобы выполнить скрипт, загруженный в активное окно Демагога, нужно нажать F2. Такой режим полезен для отладки скрипта.
Но наиболее практично выполнять скрипты, не загружая их в Демагог, а непосредственно из файла. Для этого файл скрипта должен находиться в рабочей папке
..\_Tests_. Тогда его можно увидеть в меню "Выполнить скрипт - Из файла".
Несколько примеров скриптов поставляются с дистрибутивом программы.
Могут спросить: а зачем оно надо?
Ответ такой. Встроенный интерпретатор позволяет выполнять не только команды языка Lua, но и инициировать выполнение некоторых важных опций Демагога. Для этого интерпретатор пополнен несколькими "импортированными" функциями, отсутствующими в сам
ом языке. Например:
Код: Выделить всё
ind = WActive() -- получить номер активного окна
-- обработать текст в активном окне указанным словарем
WFilter(ind, ind, HomeFolder('dic')..'Michel.dic')
WAudio(ind) -- записать аудио
ShowMessage('Работа закончена!')
Это лишь условный пример, но он демонстрирует возможность автоматизации рутинных действий пользователя.
Руководство пользователя. Сверх-краткое (пока) описание функций интерпретатора, включающее также полный перечень импортированных функций, содержится в дистрибутиве Демагога:
..\_Tests_\argo-interpreter.htm
Общие руководства (разной степени простоты или сложности) по языку Lua можно найти в Интернете.
В этой теме будут приводится примеры скриптов, в той или иной мере расширяющих функциональность Демагога.
Скрипты для Demagog
Добавлено: 16 окт 2018 13:58
flegont
Pronunciation adjustment.lua
Скрипт входит в состав дистрибутива Демагога. Позволяет произвести словарные замены по заданному набору словарей. Наборы словарей можно указывать в текстовых файлах с расширением .lst, размещенных в папке ..\dic - т.н. "плей-листах".
Порядок словарей - произвольный, какой захочет пользователь.
Можно работать, как с текстом в текущем окне, так и загрузить новый файл.
Скрипты для Demagog
Добавлено: 16 окт 2018 14:05
flegont
Collection of texts.lua
Скрипт входит в состав дистрибутива Демагога. Позволяет объединить воедино документы разных форматов, распознавание которых поддерживает Демагог: DOC, DOCX, RTF, HTML, FB2, EPUB, TXT...
Скрипты для Demagog
Добавлено: 16 окт 2018 14:07
flegont
Audio recording and computer shutdown.lua
Скрипт входит в состав дистрибутива Демагога. Позволяет выполнить запись аудио с последующим выключением компьютера.
Скрипты для Demagog
Добавлено: 17 окт 2018 17:06
tonio_k
В плане развития направления скриптов, вот какие бы направления хотелось бы реализовать:
1) Функционал "Сериалы". Скрипт, который бы разбивал файл книги на части по шаблону 0001, 0002 и т.д. Затем по циклу каждый файл по порядку прогнать через словари, ну и запись в аудио параллельно.
2) Замены по правилам rex.
В теле скрипта указать список правил rex (грубо говоря скопировать из словарейu REX) и построчно применить их к тексту. Что бы при этом показывал время работы в долях секунды и количество произведенных замен. Это реализация поднятой
тут темы, ну и вообще пригодится для разовых замен и тестирования правил
Отправлено спустя 3 минуты 35 секунд:
К п.1 Уточнение: цикл: файл открыть, применить словари, переписать файл, записать в mp3
Отправлено спустя 35 минут 39 секунд:
к п.2 пример для расчета времени работы части кода
► Показать
local x = os.clock() -- запоминаем время (х) на начало работы
local s = 0
for i=1,100000 do s = s + i end -- это цикл для создания нагрузки на процессор
print(string.format("elapsed time: %.2f\n", os.clock() - x))-- текущее время минус время (х) на начало работы = затраченное время. Результат будет в миллисекундах
Отправлено спустя 1 час 14 минут 23 секунды:
К п.2 Такая мысль. Вместо того что бы доробатывать модуль поиска:
каждое правило из тела скрипта сохранять в файл
temp.rex куда перезаписывается правило REX из тела скрипта, затем полученый словарь применить к тексту (с замерами по времени). Затем берём следующее правило и т.д.
Отправлено спустя 5 минут 18 секунд:
... Только это не покажет количество срабатываний
Скрипты для Demagog
Добавлено: 17 окт 2018 19:44
flegont
В теле скрипта указать список правил rex
Тут надо поэкспериментировать. У Lua собственная система кодов для поиска в тексте, и некоторые символы, в т.ч. обратный слэш, воспринимаются как служебные.
Поэтому строковые значения надо заключать в двойные квадратные скобки, тогда все символы воспримутся, как они есть:
s = [[\bвсе пропало\b]]; print(s)
s = [[\w+]]; print(s)
Останется проблема с использованием в теле скрипта юникодных символов, например:
s = [[fsʲˈɵ prɐpˈalə]]; print(s) Результат: fs??? pr?p?al?

Скрипты для Demagog
Добавлено: 17 окт 2018 21:18
tonio_k
Настаивать не буду, но те словари rex, которые пробегали мимо меня не содержали замен с юникодом. Так что можно попробовать работать с тем, что есть. Даже интересно узнать, работая с кодировкой ANSI может будет прирост в скорости?

Скрипты для Demagog
Добавлено: 17 окт 2018 21:36
flegont
Какого-то особого выигрыша в скорости не ожидаю, но точный ответ даст только эксперимент.
Отправлено спустя 17 часов 3 минуты 35 секунд:
Но сперва протестирую одну небольшую модификацию встроенного интерпретатора, которая должна позволить ему понимать юникод.
Скрипты для Demagog
Добавлено: 18 окт 2018 22:07
balaamster
flegont,
В стандартной библиотеке Lua мне не попался функционал работы с файловой системой.
Было бы здорово, если бы появилась функция AllFolders(folder[,mask]), которая бы возвращала таблицу с каталогами, находящимися по пути folder, а опциональный параметр mask позволял бы отфильтровать имена по маске (хотя это можно будет и через if else сделать).
С такой функцией можно и не реализовывать рекурсивный обход каталогов, а пользователь сам напишет функцию с требуемой глубиной рекурсии.
Скрипты для Demagog
Добавлено: 18 окт 2018 23:55
flegont
Функционал для работы с файлами в Lua есть, но довольно скудный. В книжке Роберто Иерусалимского это глава
22. Библиотека ввода-вывода.
Поискал в Инете:
как в Lua можно получить список папок по заданному пути? Для Windows нашел вот такое (чорт побери, кто бы мог подумать...

). В любом окне Демагога пишем строчку (путь в ней можно поменять на любой):
for dir in io.popen([[dir "C:\Program Files\" /b /ad]]):lines() do print(dir) end
Жмем F2 и в окне Статистики видим список папок в C:\Program Files
Скрипты для Demagog
Добавлено: 19 окт 2018 08:55
flegont
Функции, написанные пользователем
Как быть, если пользователь написал на Lua собственные функции, которые хочет в дальнейшем использовать в своих скриптах? Где их хранить, чтобы интерпретатор их видел?
► Показать
Рассмотрим условный (но работоспособный) пример. Пусть есть две пользовательские функции:
-- сумма двух чисел
function summa(a,b)
return a+b
end
-- квадрат числа
function kvadrat(a)
return a*a
end
Поместим тексты этих функций в файл с именем, хотя бы, mylib.lua в созданной для этого папке, например, work в рабочей папке Демагога. Тогда в любом скрипте, использующем эти функции, в самом начале необходимо будет указывать ссылку на нашу личную библиотеку:
-- скрипт
require "work/mylib"
x = 1
y = 2
print(kvadrat(summa(x,y)))
-- результат 9 в окне Статистики
Обратите внимание: в ссылке путь к библиотеке указывается с прямым слэшем. Имя файла библиотеки указывается без расширения. Кстати, путь можно указывать и с обратным слэшем, но тогда его надо удваивать: require "work\\mylib"
Таким образом можно создать сколь угодно большую пользовательскую библиотеку функций для встроенного интерпретатора.
Скрипты для Demagog
Добавлено: 19 окт 2018 10:02
tonio_k
flegont, помню вы скидывали пример скрипта типа простого шаблона "схемы" sample.lua . В дистрибутиве его нет. Может здесь в шапке его добавить? Для начинающих он нужен точно.
Скрипты для Demagog
Добавлено: 19 окт 2018 11:53
flegont
В самом первом сообщении этой темы синим цветом 5 строчек. Это, по сути и есть тот пример sample.lua. Я эти строки сейчас выделил жирным шрифтом, чтоб заметнее было
А вообще-то, надо постепенно разворачивать, углублять, детализировать нынешнее краткое описание
..\_Tests_\argo-interpreter.htm, снабдить его поясняющими примерами. Вот только времени пока нет

Скрипты для Demagog
Добавлено: 19 окт 2018 13:24
tonio_k
► Показать
homedir = [[D:\MP3\]]
hometxt = homedir..'0001.txt'
WOpen(1,hometxt)
WAudio(1)
как прописать путь из переменной
homedir в строку
WAudio так, что бы при начале записи аудио не выходило окно с предложением выбрать папку для сохранения?
Отправлено спустя 6 минут 54 секунды:
и дополню вопрос. Приведите пример Как вызвать в начале работы скрипта окно с выбором папки и результат выбора присвоить переменной
homedir , что бы её "жестко" не прописывать в теле скрипта
Скрипты для Demagog
Добавлено: 19 окт 2018 15:23
balaamster
tonio_k писал(а): ↑19 окт 2018 13:31
Приведите пример Как вызвать в начале работы скрипта окно с выбором папки и результат выбора присвоить переменной homedir , что бы её "жестко" не прописывать в теле скрипта
Можно так:
Код: Выделить всё
homedir = Folders("Выберите папку", "С:\\стартовая_папка\\по_умолчанию", true)
Где "С:\\стартовая_папка\\по_умолчанию" - путь, с которого желаете начать обзор.
true - позволит создавать новые каталоги в диалоге выбора.
Скрипты для Demagog
Добавлено: 19 окт 2018 16:42
flegont
как прописать путь из переменной homedir в строку WAudio так, что бы при начале записи аудио не выходило окно с предложением выбрать папку для сохранения?
Снять галочку:
Сервис - Общие настройки - Аудио - Спрашивать куда сохранять аудио (иначе там же, где исходный текст)
Скрипты для Demagog
Добавлено: 19 окт 2018 17:00
tonio_k
flegont писал(а): ↑19 окт 2018 16:42
Снять галочку
это надо в будущем обязательно добавить в ..\_Tests_\argo-interpreter.htm к
описанию WAudio
Скрипты для Demagog
Добавлено: 19 окт 2018 17:33
flegont
Да, добавлю.
Скрипты для Demagog
Добавлено: 19 окт 2018 18:07
tonio_k
tonio_k писал(а): ↑19 окт 2018 17:00
Снять галочку: Сервис - Общие настройки - Аудио
А может для "Спрашивать куда сохранять аудио" добавить в
WAudio как дополнительный параметр (true/false)? Иначе для "полностью автоматической" отработки скрипта, необходимо каждый раз "не забыть" убрать галочку.
Скрипты для Demagog
Добавлено: 19 окт 2018 18:48
flegont
Хорошая мысль. В следующей версии сделаю. Тогда и в argo-interpreter.htm добавлять ничего не придется

Скрипты для Demagog
Добавлено: 19 окт 2018 18:56
tonio_k
Хочу через скрипт осуществить запись в аудио предварительно разбитый файл на сериалы. Разбил на файлы 0001.txt 0002.txt
► Показать
homedir = Folders("ВЫБЕРИТЕ ПАПКУ, ГДЕ НАХОДЯТСЯ ТХТ ФАЙЛЫ", "D:\\MP3", true)
filename = '0001'
hometxt = homedir..filename..'.txt'
homemp3 = homedir..filename..'.mp3'
WOpen(1,hometxt)
WAudio(1,homemp3) -- записать в аудио текущее окно в папку MP3 в каталоге Демагога
WActive(1) -- сделать активным окно и РАЗБЛОКИРОВАТЬ его
WNew(1)
filename = '0002'
hometxt = homedir..filename..'.txt'
homemp3 = homedir..filename..'.mp3'
WOpen(1,hometxt)
WAudio(1,homemp3) -- записать в аудио текущее окно в папку MP3 в каталоге Демагога
WActive(1) -- сделать активным окно и РАЗБЛОКИРОВАТЬ его
WNew(1)
::HALT::
С чем столкнулся:
1) Демагог пытается "продолжить" сериал - приходится отключать разбивать на сериал в настройках Демагога.
Может тут тоже на уровне скрипта регулировать разбивать на сериалы или нет (true/false)?
2) Когда доходит до 0002.txt - опять начинается запись
0001.mp3 Ошибка в скрипте?
Впорос. Я правильно понял, Повторяющийся отрезок скрипта
► Показать
hometxt = homedir..filename..'.txt'
homemp3 = homedir..filename..'.mp3'
WOpen(1,hometxt)
WAudio(1,homemp3) -- записать в аудио текущее окно в папку MP3 в каталоге Демагога
WActive(1) -- сделать активным окно и РАЗБЛОКИРОВАТЬ его
WNew(1)
я могу внести в отдельный
файл.lia
и тогда скрипт уже будет выглядеть так:
► Показать
homedir = Folders("ВЫБЕРИТЕ ПАПКУ, ГДЕ НАХОДЯТСЯ ТХТ ФАЙЛЫ", "D:\\MP3", true)
filename = '0001'
require "work/файл.lia"
filename = '0002'
require "work/файл.lia"
Скрипты для Demagog
Добавлено: 19 окт 2018 19:23
flegont
function TextToAudio(homedir,filename)
local hometxt = homedir..filename..'.txt'
local homemp3 = homedir..filename..'.mp3'
WOpen(1,hometxt)
WAudio(1,homemp3)
WNew(1)
end
Поместить эту функцию в файл mylib.lua в папке work
В скрипте она будет вызываться так:
require "work/mylib" -- подключение библиотеки, ОДИН раз в начале!
...
homedir = ... -- папка где лежат текстовые файлы
filename = ... -- имя конкретного текстового файла в этой папке
...
TextToAudio(homedir,filename)
-- получили аудиофайл с тем же именем и расширением .mp3
...
Как-то так в общем...
Скрипты для Demagog
Добавлено: 19 окт 2018 22:10
balaamster
flegont писал(а): ↑18 окт 2018 23:55
for dir in io.popen([[dir "C:\Program Files\" /b /ad]]):lines() do print(dir) end
Замечательное решение, кроссплатформенное, использует функционал ОС.
Даже рекурсивный обход папок получилось сделать:
► Показать
Код: Выделить всё
startdir = Folders("ВЫБЕРИТЕ ПАПКУ ДЛЯ ОБРАБОТКИ","C:\\NST\\")
function AllFolders(path)
local list = {}
for dir in io.popen(string.format([[dir %s /b /ad]],path)):lines() do table.insert(list,path..dir.."\\") end
return list
end
function recursion_dirs(path)
dir_tree = {}
function walk_dirs(dirs_table)
if #dirs_table > 0 then
for _, i in pairs(dirs_table) do
table.insert(dir_tree,i)
walk_dirs(AllFolders(i))
end
end
end
walk_dirs(AllFolders(path))
return dir_tree
end
for i,j in pairs(recursion_dirs(startdir)) do print(i,j) end
Результатом работы сценария будет рекурсивный список путей от исходного каталога.
Ох уж эта кириллица...
Кириллица, в именах папок, ломает работу сценария:
► Показать
Default
Default User
Public
User
Ђ¤¬ЁЁбва в®а
‚ᥠЇ®«м§®ў ⥫Ё
Уже испробовал разные варианты, не помогает:
Запуск командной строки с выводом в ansi и сменой кодировки на cp1251
for dir in io.popen(string.format([[cmd /a chcp 1251 && dir %s /b /ad]],path)):lines() do print(dir) end
Запуск командной строки с выводом в unicode и сменой кодировки на utf-8
for dir in io.popen(string.format([[cmd /u chcp 65001 && dir %s /b /ad]],path)):lines() do print(dir) end
P.S. попробовал в интерпретаторе lua53.exe - кириллица выводится корректно.
Можно ли как-то поправить кириллицу во встроенном интерпретаторе?
Скрипты для Demagog
Добавлено: 19 окт 2018 23:27
flegont
Такая проблема у меня была несколько лет назад с тестовой программкой на Дельфи, которая выводила русский текст на консоль. В этом маленьком черном окошке всегда были кракозябры вместо кириллицы.
Тогда я встал мышью на заголовок командного окна, правой клавишей - выпадающее меню - свойства - шрифт. И поменял шриф на другой, не помню какой, толи люцинда консоле, толи еще что. И вывод кириллицы стал нормальным.
Но это надо делать именно в сеансе, запущенном программой.
А этот рекурсивный скрипт выводит тучу таких командных окон, но на долю секунды - не успеть ничего сделать

Скрипты для Demagog
Добавлено: 20 окт 2018 02:44
tonio_k
flegont писал(а): ↑19 окт 2018 16:42
Снять галочку: Сервис - Общие настройки - Аудио - Спрашивать куда сохранять аудио (иначе там же, где исходный текст)
Вопрос, в скрипте для
WAudio предусмотрено принудительное указание другой папки сохранения MP3? Например:
► Показать
Код: Выделить всё
homedir = Folders("ВЫБЕРИТЕ ПАПКУ, КУДА СОХРАНИТЬ MP3", "D:\\MP3", true)
--тут долгая работа словарей
WAudio(ind,homedir)
Из этих строк скрипта сейчас всего два варианта событий:
1) либо (снята галочка) mp3 файлы падают в тот же каталог, где книга источник
2) либо (возвращаем галочку) после долгой работы словарей скрипт встаёт на паузу и ждет действий пользователя - указать в какую папку сохранять mp3
Отправлено спустя 1 час 7 минут 2 секунды:
Пытаясь прописать команду
WSave - сохранить резервную копию обработанного словарями текст (перед самым началом записи в mp3 -
WAudio), случайно обнаружил, что аудиофайлы начинают помещаться именно в ту папку, куда и был сохранен этот самый текст.
► Показать
homedir = Folders("ВЫБЕРИТЕ ПАПКУ, КУДА СОХРАНИТЬ MP3", "D:\\MP3", true)
--тут долгая работа словарей
WSave(ind,homedir..'last_text.txt')
WAudio(ind,homedir)
Это есть ответ на мой же вопрос выше
Если этот резервный файл кому-то будет мешать, то его можно удалить добавив строку
os.remove(homedir..'last_text.txt')
Тогда новый вопрос, как вместо
last_text.txt прописать так, что бы указывалось имя открытого файла в окне ind?
Скрипты для Demagog
Добавлено: 20 окт 2018 09:47
flegont
в скрипте для WAudio предусмотрено принудительное указание другой папки сохранения MP3?
Пока нет, но будет соответствующий 2-й параметр: папка назначения. Ее указание приведет к игнорированию запроса папки назначения, если он был задан в Настройках. Если 2-й параметр задан, как пустая строка, то запрос папки назначения также будет игнорирован, и папкой назначения будет считаться та, где лежит озвучиваемый текст.
аудиофайлы начинают помещаться именно в ту папку, куда и был сохранен этот самый текст.
Когда в Настройках снята галка о запросе папки назначения для аудио, то аудио-файлы размещаются там же, где находится озвучиваемый текст
что бы указывалось имя открытого файла в окне ind?
В следующей версии добавлю функцию WName(i) - имя файла, открытого в окне i.
Скрипты для Demagog
Добавлено: 20 окт 2018 17:10
balaamster
Проблему с выводом кириллицы нашёл на просторах интернета.
Как оказалось, при запуске cmd-команд из lua, необходимо смену кодировки передавать по конвейеру:
А не в виде последовательного выполнения команд.
В попытках решить проблему, сегодня пришёл к более простому решению, нежели написал вчера:
► Показать
Код: Выделить всё
function recursion_dirs(path)
local tmp_file = string.format("%s%s", os.getenv("LOCALAPPDATA"), "\\temp\\scr_temp.txt") -- Задаём путь ко временному файлу
os.remove(tmp_file) -- Удаляем временный файл, если он сохранился по какой-то причине
local dir_tree_cmd = string.format([[chcp 1251 | for /R %s %%d in (.) do echo %%d>>%s]], startdir, tmp_file)
os.execute(dir_tree_cmd) -- Получаем все подкаталоги через цикл for из cmd.
local dirs = {}
for str in io.lines(tmp_file) do table.insert(dirs,string.sub(str,1,-3)) end -- Заполняем таблицу путями каталогов.
os.remove(tmp_file) -- Удаляем временный файл.
return dirs
end
Функция принимает на входе путь к стартовому каталогу, возвращает таблицу со стартовым каталогом и его подкаталогами.
Скрипты для Demagog
Добавлено: 20 окт 2018 20:12
flegont
!! Очень полезная информация

Скрипты для Demagog
Добавлено: 24 окт 2018 15:00
tonio_k
WName(i)
► Показать
homedir = Folders("ВЫБЕРИТЕ ПАПКУ, КУДА СОХРАНЯТЬ MP3-файлы\nПапка по умолчанию: ", "D:\\MP3", true)
ind = WActive() -- получить номер активного окна
namebook = WName(ind) -- получить имя книги из активного окна
--ОБРАБОТКА текста книги по словарю:
homedic = HomeFolder('dic')-- Полный путь к словарю с подпапкой 'dic'
slovar1 = '00_.rex' -- путь к словарю 1
WFilter(ind,ind,homedic..slovar1,true) -- текущее окно обработать по словарю1 и поместить результат в окно ind
--СОХРАНЕНИЕ ОБРАБОТАННОГО ТЕКСТА В ПАПКУ homedir
WSave(ind,homedir..namebook)
Так как WName выдает имя файла с расширением и полный путь к этому файлу, то как можно открываемый из одной папки файл
Моя книга.fb2 обработать по словарю и сохранить в другую папку но уже
Моя книга.txt?
По хорошему, я ожидал, что
WName будет выдавать
только текст наименования файла без расширения и полного пути:
Моя книга
Тогда скрипт будет так выглядеть:
► Показать
homedir = Folders("ВЫБЕРИТЕ ПАПКУ, КУДА СОХРАНЯТЬ MP3-файлы\nПапка по умолчанию: ", "D:\\MP3", true)
ind = WActive() -- получить номер активного окна
namebook = WName(ind) -- получить имя книги из активного окна
ОБРАБОТКА текста книги по словарю:
homedic = HomeFolder('dic')-- Полный путь к словарю с подпапкой 'dic'
slovar1 = '00_.rex' -- путь к словарю 1
WFilter(ind,ind,homedic..slovar1,true) -- текущее окно обработать по словарю1 и поместить результат в окно ind
--СОХРАНЕНИЕ ОБРАБОТАННОГО ТЕКСТА В ПАПКУ homedir
WSave(ind,homedir..namebook..'.txt')
А этот сохраненный файл можно так же через скрипт открть и поставить на запись в mp3:
► Показать
WOpen(ind,homedir..namebook..'.txt')
WAudio(ind,homedir,true)
Отправлено спустя 10 минут 37 секунд:
может
WName(i) добавить параметр
false - только имя без расширения и пути?
Скрипты для Demagog
Добавлено: 24 окт 2018 15:25
flegont
Думал об этом. Но, я предпочитаю извлекать
полные имена файлов, чтобы можно было их использовать для обращения к файлам. Для получения кратких имен (т.е. без путей), и отдельно путей (без имен), хочу создать 2 функции для интерпретатора:
ExtractFileName(full_file_name)
ExtractFilePath(full_file_name)
Их можно написать, собственно, на Lua.
Ну, можно и 3-ю:
ChangeFileExt(file_name, new_ext) для изменения типа файла.
Например: txtfile = ChangeFileExt(mp3file, '.txt')
Еще пример:
simple_name = ChangeFileExt(ExtractFileName(full_file_name), '') -- извлекает имя без пути и без расширения
P.S. А может, всё это уже изобретено

ведь язык Lua не вчера родился. Надо в Инете поискать.
Скрипты для Demagog
Добавлено: 24 окт 2018 15:44
balaamster
tonio_k, Как временное решение можно:
Код: Выделить всё
-- разбиваем путь на компоненты
path_parts = string.split(WName(ind),"\\")
-- берём последний элемент пути (имя файла) и удаляем расширение
namebook = string.gsub(path_parts[#path_parts],"%.%w+$","")
flegont,
как я понял, string.split - это уже функция добавленная в Demagog? В справочнике по lua её не нашёл, хотя функция очень нужная и полезная.
Также как и отсутствие обращения к элементу строки по индексу, как в python, очень огорчило. Пришлось набросать преобразование строки в таблицу.
Отправлено спустя 58 минут 50 секунд:
flegont писал(а): ↑24 окт 2018 15:25
P.S. А может, всё это уже изобретено
Скорее всего, уже есть библиотеки для работы с путями.
Мне, например, интересно "изобретать велосипед", в качестве средства познакомиться с lua поближе.
Набросал черновой вариант подобных функций. Конечно, нужно их оттестировать на разных тестовых строках и, возможно, добавить ещё какие-нибудь проверки.
► Показать
Код: Выделить всё
function ExtractFileName(full_file_name)
if type(full_file_name) ~= "string" then return nil end
local splitted_path = string.split(full_file_name,"\\")
local filename = string.gsub(splitted_path[#splitted_path ],"%.%w+$","")
return filename
end
function ExtractFilePath(full_file_name)
if type(full_file_name) ~= "string" then return nil end
local splitted_path = string.split(full_file_name,"\\")
local filepath = table.concat(splitted_path,"\\",1,#splitted_path-1)
return filepath.."\\"
end
function ChangeFileExt(file_name, new_ext)
if type(file_name) ~= "string" or type(new_ext) ~= "string" then return nil end
return (string.gsub(file_name,"%.%w+$","."..new_ext))
end
Скрипты для Demagog
Добавлено: 24 окт 2018 17:35
flegont
string.split - это уже функция добавленная в Demagog?
..\profiles\
calculator.lua
Я уже упоминал о "личных" библиотеках пользователя. так вот
calculator.lua -
это личная библиотека Демагога, она подключается автоматически при запуске любого скрипта.
В ней содержатся функции, написанные чисто на Lua, при этом они могут использовать и функции, импортированные из Демагога.
Функция string.split как раз там и прописана.
От версии к версии ..\profiles\
calculator.lua может изменяться. Все изменения в нем я стараюсь делать, сохраняя совместимость с предыдущими версиями, чтобы ранее созданные скрипты оставались работоспособными.
интересно "изобретать велосипед", в качестве средства познакомиться с lua поближе
Мне тоже. Вот, только что изобрел - одна функция вместо трех. Принимает полное имя файла и возвращает массив из 3-х строк: путь, краткое имя без расширения, расширение.
► Показать
Код: Выделить всё
function SplitFileName(s)
local a = {'','',''}
local dot = false
local d = #s+1
for k = #s,1,-1 do
b = string.sub(s,k,k)
if (b == '.') and not dot then
a[3] = string.sub(s,k,#s)
d = k
dot = true
end
if (b == '\\') or (b == '/') then
a[2] = string.sub(s,k+1,d-1)
a[1] = string.sub(s,1,k)
return a
end
end
a[2] = string.sub(s,1,d-1)
return a
end
Пример:
► Показать
Код: Выделить всё
s = [[d:\qwerty\йцукен.1.txt]]
a = SplitFileName(s)
for i = 1,#a do
print(i,a[i])
end
Результат:
1 d:\qwerty\
2 йцукен.1
3 .txt
А вот, как поменять расширение имени файла, к примеру, с .txt на .lua:
Код: Выделить всё
s = [[d:\qwerty\йцукен.1.txt]]
a = SplitFileName(s)
s = a[1]..a[2]..'.lua'
print(s)
Результат:
d:\qwerty\йцукен.1.lua
Также как и отсутствие обращения к элементу строки по индексу, как в python
Да, строки в Lua - статические. Как я понимаю, это сделано ради быстродействия.
Приходится, для получения k-го элемента строки, изворачиваться как-то так: b = string.sub(s,k,k)
Скрипты для Demagog
Добавлено: 24 окт 2018 23:56
flegont
Включил SplitFileName() в ..\profiles\calculator.lua, дописал о ней в мануале ..\_Tests_\argo_interpreter.htm и обновил дистрибутив на сайте. Теперь интерпретатор эту функцию видит.
Скрипты для Demagog
Добавлено: 26 окт 2018 12:57
tonio_k
подскажите как lua, например, z=123 превратить в формат 00ч 02м 03с ?
Скрипты для Demagog
Добавлено: 26 окт 2018 14:39
balaamster
tonio_k писал(а): ↑26 окт 2018 12:57
превратить в формат 00ч 02м 03с
По идее как-то так:
► Показать
Код: Выделить всё
z=123
h = math.floor(z / 60^3)
m = math.floor(z / 60)
s = math.floor(z % 60)
result = string.format("%02dч. %02dм. %02dс.", h, m, s)
print(result)
Отправлено спустя 51 минуту 8 секунд:
Прошу прощения, ошибся в формулах, плохой из меня математик:
Код: Выделить всё
z=123
h = math.floor(z / 60^2)
m = math.floor((z % 60^2) / 60)
s = math.floor(z % 60)
result = string.format("%02dч. %02dм. %02dс.", h, m, s)
print(result)
Скрипты для Demagog
Добавлено: 26 окт 2018 18:52
flegont
А вот так можно просто перевести системное время в дату и время
(дата - в англо-американском формате):
print(os.date("%c"))
Пример результата:
10/26/18 18:46:55
Скрипты для Demagog
Добавлено: 26 окт 2018 19:31
tonio_k
Варианты "вывода" системной даты в Европейском формате:
print(os.date("%d.%m.%Y")..' '..os.date("%X"))
Пример результата: 26.10.2018 19:21:24
print(os.date("%d.%m.%Y"))
Пример результата: 26.10.2018
print(os.date("%X"))
Пример результата: 19:21:24
Скрипты для Demagog
Добавлено: 27 окт 2018 11:04
flegont
UPDATE 27.10.2018 14:37
Функция Fragments(s, fragsize, parag), разбивающая текст на фрагменты с заданным количеством символов
Возвращает список строк-фрагментов.
Параметр
s - это ооочччень длинная строка, представляющая собой текст некоей книги. Может быть получена, например, извлечением текста из документа, загруженного в окне Демагога: s = WText(i).
Необязательный параметр
parag - если true, то фрагменты собираются из абзацев, иначе (по умолчанию) - из предложений.
Сборка фрагментов из абзацев может потребоваться:
а) для обеспечения б
ольшей логической полноты фрагмента;
б) для правильного деления на фрагменты текста, являющегося
словарем.
► Показать
Код: Выделить всё
-- Деление текста на фрагменты заданного размера (в символах)
function Fragments(s,fragsize,parag)
local a
s = string.gsub(s,'\9',' ') -- табуляция ==> пробел
s = string.gsub(s,'%.%.%.','\133') -- 3 точки подряд ==> символ "многоточие"
if not parag then -- фрагменты собираются из предложений
-- вставляем разделительный символ в конце каждого предложения
-- концом предложения считаем один из символов . ; ! ?
s = string.gsub(s,'!','!\3')
s = string.gsub(s,';',';\3')
s = string.gsub(s,'%?','?\3')
s = string.gsub(s,'%.','.\3')
a = string.split(s,'\3')
else -- фрагменты собираются из абзацев
a = string.split(s,'\r')
end
local b = {}
local m = 0
local c = ''
local j = 1
for i = 1,#a do -- создаем список фрагментов
if (m >= fragsize) or (i ==#a) then
b[j] = c
c = a[i]
m = 0
j = j+1
else
m = m+#a[i]
if not parag then c = c..a[i] else c = c..'\r'..a[i] end
end
end
return b
end
Пример скрипта, использующего эту функцию. Создание серии файлов из текста в активном окне.
► Показать
Код: Выделить всё
s = WText(WActive())
b = Fragments(s,6000)
for i = 1,#b do
fname = 'work\\extract\\N'.. string.format("%04d",i)..'.txt'
SaveToFile({b[i]},fname)
end
Результат: серия файлов в папке
work\extract в рабочей папке Демагога. Имена файлов:
N0001.txt, N0002.txt ... и т.д.
Скрипты для Demagog
Добавлено: 28 окт 2018 19:06
balaamster
Попробовал написать функцию для перебора подкаталогов, с учётом появившейся AllFolders.
Возможно, кому-нибудь пригодится.
recursion_dirs(path[, dmask])
path - строка, путь к стартовому каталогу
dmask - строка, маска для отбора каталогов, необязательный параметр.
Функция возвращает таблицу со списком подкаталогов (с полными путями), включая стартовый каталог.
Пример использования:
► Показать
Код: Выделить всё
ext = ".txt"
-- стартовый каталог
path = "C:\\books\\"
-- или:
-- path = Folders("caption", "C:\\books\\")
function recursion_dirs(path, dmask, dir_table)
if type(path) ~= "string" then return nil end
if path:sub(-1,-1) ~= "\\" then path = path.."\\" end
local dir_table = dir_table or {path}
local collection = AllFolders(path, dmask)
if #collection ~= 0 then
for _,i in pairs(collection) do
if i ~= "." and i ~= ".." then
local i_path = path..i.."\\"
dir_table[#dir_table+1] = i_path
recursion_dirs(i_path,dmask,dir_table)
end
end
end
return dir_table
end
-- получаем все подкаталоги
all_subdirs = recursion_dirs(path)
-- таблица для списка файлов
all_files_with_ext = {}
-- получаем все файлы, с заданным расширением (ext = ".txt"), находящиеся в подкаталогах из списка, и заносим их полные пути в таблицу.
for _,i in pairs(all_subdirs) do
for j, k in pairs(AllFiles(i,ext)) do
table.insert(all_files_with_ext,i..k)
end
end
-- распечатываем список путей
for _,i in pairs(all_files_with_ext) do print(i) end
Скрипты для Demagog
Добавлено: 28 окт 2018 19:55
tonio_k
flegont писал(а): ↑27 окт 2018 11:04
Пример скрипта, использующего эту функцию.
1) А можно эту функцию и сам скрипт объединить в один скрипт? т.е. Саму функцию в шапку поместить. В таком виде будет работать?
► Показать
Код: Выделить всё
-- Деление текста на фрагменты заданного размера (в символах)
function Fragments(s,fragsize,parag)
local a
s = string.gsub(s,'\9',' ') -- табуляция ==> пробел
s = string.gsub(s,'%.%.%.','\133') -- 3 точки подряд ==> символ "многоточие"
if not parag then -- фрагменты собираются из предложений
-- вставляем разделительный символ в конце каждого предложения
-- концом предложения считаем один из символов . ; ! ?
s = string.gsub(s,'!','!\3')
s = string.gsub(s,';',';\3')
s = string.gsub(s,'%?','?\3')
s = string.gsub(s,'%.','.\3')
a = string.split(s,'\3')
else -- фрагменты собираются из абзацев
a = string.split(s,'\r')
end
local b = {}
local m = 0
local c = ''
local j = 1
for i = 1,#a do -- создаем список фрагментов
if (m >= fragsize) or (i ==#a) then
b[j] = c
c = a[i]
m = 0
j = j+1
else
m = m+#a[i]
if not parag then c = c..a[i] else c = c..'\r'..a[i] end
end
end
return b
end
--------------------------------------------------------------------------------
s = WText(WActive())
b = Fragments(s,6000)
for i = 1,#b do
fname = 'work\\extract\\N'.. string.format("%04d",i)..'.txt'
SaveToFile({b[i]},fname)
end
2) Было бы не плохо добавить в эту
function Fragments вставку в начале и конце название файла и номер части (как в настройках сериалов Демагог:
"%1". Serie %2)
Отправлено спустя 12 минут 22 секунды:
3) А можно еще пример функции, которая будет открывать эти разбитые N0001.txt, N0002.txt ... и т.д. файлы, применять словарь dic и перезаписывать измененный файл?
Скрипты для Demagog
Добавлено: 28 окт 2018 20:36
flegont
1) Нет. Работа закончится, как только выполнение дойдет до строчки
return b - завершить работу функции, вернув список фрагментов
b
2) Функцию
Fragments я включу в состав функций интерпретатора, как она есть. Для этого не нужно ничего менять в программе, вставлю в "личную библиотеку Демагога" и всё. (Со своим экземпляром Демагога я это уже проделал

)
На ее основе можно уже создать функцию пользователя, делающую сериал из файла fname. Назовем ее к примеру
MakeSeries(fname, fragsize, parag, header, ender) - параметры - header и ender - это шаблоны начальной и конечной фраз в каждой серии.
3) Сразу несколько идей, надо проверить...
Скрипты для Demagog
Добавлено: 28 окт 2018 22:25
flegont
Функция
WSeries(i, folder, fragsize, parag, header, ender, startnum)
Создает сериал из документа, открытого в окне
i
folder - папка назначения;
fragsize - размер серии в символах;
Необязательные параметры:
parag = true -
набор фрагментов по абзацам, false - по предложениям; по умолчанию
false;
header - заголовочная фраза серии, к которой автоматически добавится ее номер;
ender - последняя фраза серии, к которой автоматически добавится ее номер.
startnum - начальный номер серии, по умолчанию 1
Код: Выделить всё
function WSeries(i, folder, fragsize, parag, header, ender, startnum)
local fname
local s = WText(i)
local b = Fragments(s,fragsize,parag)
local k = #folder
if not startnum then
startnum = 1
end
if string.sub(folder,k,k) ~= '/' and string.sub(folder,k,k) ~= '\\' then
folder = folder..'\\'
end
for i = 1,#b do
fname = folder..string.format("%04d",(i+startnum-1))..'.txt'
if header then
b[i] = header..' '..(i+startnum-1)..'\r'..b[i]
end
if ender then
b[i] = b[i]..'\r'..ender..' '..(i+startnum-1)
end
SaveToFile({b[i]},fname)
end
end
Пример использования:
WSeries(11, [[d:/MP3]], 6000, true, 'Серия', 'Конец серии')
Имена файлов серий имеют вид: 0001.txt, 0002.txt ... и т.д.
Замечание. Конечный слэш в имени папки назначения можно не указывать, тогда он добавится автоматически.
Скрипты для Demagog
Добавлено: 28 окт 2018 22:37
tonio_k
flegont писал(а): ↑28 окт 2018 22:25
true, 'Серия', 'Конец серии'
хотел уточнить, а автоматическая нумерация сериала и его начальный номер (%2) Блок 1, Бок 2 и т.д?
Отправлено спустя 2 минуты 12 секунд:
Уточню, где можно поменять начальный номер?
Скрипты для Demagog
Добавлено: 28 окт 2018 22:43
flegont
Пока что я сделал автоматическое прибавление номера серии к заголовочной и оконечной фразе, а начальное значение всегда = 1. Но это не проблема. Добавлю еще один необязательный параметр startnum, по умолчанию 1
Скрипты для Demagog
Добавлено: 28 окт 2018 22:50
flegont
Добавил параметр startnum, отредактировалсообщение #42
Отправлено спустя 9 часов 2 минуты 45 секунд:
Итак, у нас теперь есть функция WSeries, которая мигом нашинкует

сериал из документа в указанном ей окне. Но, нужна еще одна функция! Чтобы смогла к каждому файлу сериала применить заданный список словарей и сохранить измененный текст сериии, в том же месте, под тем же именем.
Кажется, всё просто. Однако, вспомним, что для словарей формата dic есть 2 режима работы.
Мы легко можем написать список словарей в виде {словарь1, словарь2, словарь3,...}, где словарьN - это имя словаря, заданное, как выражение или, как строковая переменная.
Ну, и как мы укажем нашей функции, что "Какой-то_там_словарь.dic" надо применить к тексту по "быстрому алгоритму", а "Другой_словарь.dic" - "прямым перебором"?!
(продолжение следует)
Скрипты для Demagog
Добавлено: 29 окт 2018 10:08
tonio_k
Вот тут хочу высказать пожелание, которую я не озвучивал, так как думал, что это можно реализовать за счёт скрипта.
В самой программе Демагог для каждого словаря dic индивидуально сделать выбор метода обработки для каждого словаря вместо одного глобального. В глобальных настройках убирая галочку по умолчанию пусть открывается окно: "Выбор алгоритма" - как отдельное окно, которое открывает текстовый файл со списком словарей dic и в нем выставить параметр true/ false. А демагог будет обращаться к этому файлу для получения информации по какому методу делать обработку словарями. Тогда в скрипте достаточно будет выбрать список словарей, а они уже отработают как в глобальных настройках, согласно файлу со списком алгоритмов.
Скрипты для Demagog
Добавлено: 29 окт 2018 10:23
balaamster
flegont писал(а): ↑29 окт 2018 07:53
у, и как мы укажем нашей функции, что "Какой-то_там_словарь.dic" надо применить к тексту по "быстрому алгоритму", а "Другой_словарь.dic" - "прямым перебором"?!
Можно попробовать передавать список словарей в виде вложенных таблиц.
Код: Выделить всё
dicts = {{"словарь1", true}, {"словарь2",false}, {"словарь3"},...}
for _, d in pairs(dicts) do
dict = HomeFolder("dic")..d[1]
if d[2] == nil then
mode = true
else
mode = d[2]
end
print(dict,mode)
--тут применяем словари
end
С учётом аналогичного поведения WFilter, если режим не указан, то mode=true, по умолчанию
Скрипты для Demagog
Добавлено: 29 окт 2018 11:05
flegont
Да, я пришел к той же идее. И чтобы упростить жизнь пользователю (в том числе себе), записывать список словарей как-то так:
Код: Выделить всё
diclist =
{
'словарь1.dic',
'словарь2.rex',
'словарь3.dic',
...
{'словарьX.dic',false},
...
'словарьN.dic'
}
Чтобы в виде вложенной таблицы из 2-х элементов записывать лишь в том случае, когда dic-словарь применяется прямым перебором. Но, и указанная вами полная запись так же будет работать.
Код: Выделить всё
...
b = diclist[j]
if type(b) == 'table' then
d = b[1]
mode = b[2]
else
d = b
mode = true
end
...
Отправлено спустя 18 минут 10 секунд:
Хм... Тогда и еще более краткая краткая запись
Код: Выделить всё
diclist =
{
'словарь1.dic',
'словарь2.rex',
'словарь3.dic',
...
{'словарьX.dic'},
...
'словарьN.dic'
}
будет означать алгоритм "прямого перебора"!
Получится: b[1] = 'словарьX.dic'; b[2] = nil
А значение nil эквивалентно false и получим mode = false -- алгоритм прямого перебора
Скрипты для Demagog
Добавлено: 29 окт 2018 12:14
flegont
Функция
FilterToAll(folder, mask, diclist)
Применяет к файлам в папке
folder, имена которых отвечают маске
mask, словари, перечисленные в списке
diclist.
Возвращает два значения: количество обработанных файлов и количество примененных словарей.
Список словарей задается в виде 2-мерной таблицы:
diclist = { {'словарь1', mode'}, {'словарь2', mode}, ... {'словарьN', mode} }
mode = true, если dic-словарь применяется по быстрому алгоритму и false, если прямым перебором. По умолчанию:
true.
Допускается упрощенная запись списка словарей:
diclist = {'словарь1', ... {'словарьX'}, ... } - т.е. в фигурные скобки заключается только имя dic-словаря, применяемого прямым перебором.
Код: Выделить всё
function FilterToAll(folder, mask, diclist)
local b, d, mode
local k = #folder
if string.sub(folder,k,k) ~= '/' and string.sub(folder,k,k) ~= '\\' then
folder = folder..'\\'
end
local a = AllFiles(folder,mask)
for i = 1,#a do
WOpen(0,folder..a[i])
for j = 1,#diclist do
b = diclist[j]
if type(b) == 'table' then
d = b[1]
mode = b[2]
else
d = b
mode = true
end
WFilter(0,0,d,mode)
end
WSave(0,folder..a[i])
end
WNew(0)
return #a, #diclist
end
Пример использования:
Код: Выделить всё
WSeries(11, [[d:/MP3]], 6000, true, 'Серия', 'Конец серии')
h = HomeFolder('dic')
diclist =
{
h..'vse_vsyo.rex',
{h..'Michel.dic'}
}
x, y = FilterToAll([[d:/MP3]], '0*.txt', diclist)
ShowMessage('Готово!\13Обработано файлов: '..x..'\13Применено словарей: '..y)
Важное замечание. Следует быть внимательным при указании папки назначения и маски выбора файлов. Стоит ошибиться в папке назначения или задать слишком свободную маску, например *.txt или вовсе *.*, как банда словарей зверски обработает то, что совершенно не нужно
Если указать несуществующую папку назначения, то удар будет нанесен по корневой папке Демагога
Возникает мысль о добавлении в эту функцию каких-то мер защиты от неосторожных действий пользователя

Скрипты для Demagog
Добавлено: 29 окт 2018 12:16
tonio_k
Скажите пожалуйста мне показалось, или
WAudio записывает текст в аудио с предварительной обработкой по активированным галочкой в самой программе словарям?
► Показать
Код: Выделить всё
cap = 'Выключить компьтер после записи аудио?'
itms = {' ДА',' НЕТ'}
a = Menu(cap,itms)
if a == 0 then goto HALT end
if a == 1 then
ShowMessage('После записи аудио, ПК будет выключен!')
end
ind = WActive() -- получить номер текущего окна
confirm = WAudio(ind) -- записать в аудио текущеее окна
if (a == 1) and confirm then
os.execute('shutdown /s') -- выключить компьютер
end
::HALT::
т.е. перед каждым запуском скрипта нужно убирать галочки что бы не было двойной обработки (если словари до записи уже применялись в скрипте к тексту) + исключить риск неверного применения словарей