- -- txt2fb2.lua, Версия 3
- local dtLast, bQuit=0, false
- --local CR_LF='\r\n'
- local CR_LF='\n'
- local tin=table.insert
- local F=far.Flags
- local blank={
- [[<?xml version="1.0" encoding="utf-8"?>]];
- [[<FictionBook>]];
- [[<description>]];
- [[<title-info>]];
- [[<genre>#Genre#</genre>]];
- [[<author>]];
- [[<first-name>#AuName#</first-name>]];
- [[<last-name>#AuFam#</last-name>]];
- [[</author>]];
- [[<book-title>#Title#</book-title>]];
- [[<annotation>#Annotation#</annotation>]];
- [[<date>#Year#</date>]];
- [[<lang>ru</lang>]];
- [[<sequence name="#Seq_Name#" number="#Seq_Number#"/>]];
- [[</title-info>]];
- [[</description>]];
- [[<body>]];
- [[<title>]];
- [[</title>]];
- [[<section>]];
- [[</section>]];
- [[</body>]];
- [[</FictionBook>]];
- }
- local GenreList = {
- {Text='Фантастика, Фэнтези';
- Sub={
- {Code='sf_history'; Text='Альтернативная история'};
- {Code='sf_action'; Text='Боевая фантастика'};
- {Code='sf_epic'; Text='Эпическая фантастика'};
- {Code='sf_heroic'; Text='Героическая фантастика'};
- {Code='sf_detective'; Text='Детективная фантастика'};
- {Code='sf_cyberpunk'; Text='Киберпанк'};
- {Code='sf_space'; Text='Космическая фантастика'};
- {Code='sf_social'; Text='Социально-философская фантастика'};
- {Code='sf_horror'; Text='Ужасы и Мистика'};
- {Code='sf_humor'; Text='Юмористическая фантастика'};
- {Code='sf_fantasy'; Text='Фэнтези'};
- {Code='sf'; Text='Научная фантастика'};
- {Code='child_sf'; Text='Детская фантастика'};
- {Code='love_sf'; Text='Любовная фантастика'};
- };
- };
- {Text='Детективы и Боевики';
- Sub={
- {Code='det_classic'; Text='Классические детективы'};
- {Code='det_police'; Text='Полицейские детективы'};
- {Code='det_action'; Text='Боевики'};
- {Code='det_irony'; Text='Иронические детективы'};
- {Code='det_history'; Text='Исторические детективы'};
- {Code='det_espionage'; Text='Шпионские детективы'};
- {Code='det_crime'; Text='Криминальные детективы'};
- {Code='det_political'; Text='Политические детективы'};
- {Code='det_maniac'; Text='Маньяки'};
- {Code='det_hard'; Text='Крутой детектив'};
- {Code='thriller'; Text='Триллеры'};
- {Code='detective'; Text='Детективы'};
- {Code='sf_detective'; Text='НФ детективы'};
- {Code='child_det'; Text='Детские детективы'};
- {Code='love_detective'; Text='Остросюжетные любовные романы'};
- };
- };
- {Text='Проза';
- Sub={
- {Code='prose_classic'; Text='Классическая проза'};
- {Code='prose_history'; Text='Историческая проза'};
- {Code='prose_contemporary'; Text='Современная проза'};
- {Code='prose_counter'; Text='Контркультура'};
- {Code='prose_rus_classic'; Text='Русская классика'};
- {Code='prose_su_classics'; Text='Советская классика'};
- {Code='humor_prose'; Text='Юмористическая проза'};
- {Code='prose_military'; Text='Военная проза'};
- {Code='child_prose'; Text='Детская проза'}
- }
- };
- {Text='Любовные романы';
- Sub={
- {Code='love_contemporary'; Text='Современные любовные романы'};
- {Code='love_history'; Text='Исторические любовные романы'};
- {Code='love_detective'; Text='Остросюжетные любовные романы'};
- {Code='love_short'; Text='Короткие любовные романы'};
- {Code='love_erotica'; Text='Эротика'};
- {Code='love_sf'; Text='Любовная фантастика'}
- }
- };
- {Text='Приключения';
- Sub={
- {Code='adv_western'; Text='Вестерны'};
- {Code='adv_history'; Text='Исторические приключения'};
- {Code='adv_indian'; Text=' Приключения: Индейцы'};
- {Code='adv_maritime'; Text=' Морские приключения'};
- {Code='adv_geo'; Text=' Путешествия и География'};
- {Code='adv_animal'; Text=' Природа и Животные'};
- {Code='adventure'; Text=' Приключения: Прочее'};
- {Code='child_adv'; Text=' Детские приключения'};
- }
- };
- {Text='Детские';
- Sub={
- {Code='child_tale'; Text='Сказки'};
- {Code='child_verse'; Text='Детские стихи'};
- {Code='child_prose'; Text='Детская проза'};
- {Code='child_sf'; Text='Детская фантастика'};
- {Code='child_det'; Text='Детские остросюжетные'};
- {Code='child_adv'; Text='Детские приключения'};
- {Code='child_education'; Text='Детская образовательная'};
- {Code='children'; Text='Детские: Прочее'}
- }
- };
- {Text='Поэзия и драматургия';
- Sub={
- {Code='dramaturgy'; Text='Драматургия'};
- {Code='poetry'; Text='Поэзия'};
- {Code='humor_verse'; Text='Юмористические стихи'};
- {Code='child_verse'; Text='Детские стихи'}
- }
- };
- {Text='Старинная литература';
- Sub={
- {Code='antique_ant'; Text='Античная литература'};
- {Code='antique_european'; Text='Европейская старинная литература'};
- {Code='antique_russian'; Text='Древнерусская литература'};
- {Code='antique_east'; Text='Древневосточная литература'};
- {Code='antique_myths'; Text='Мифы. Легенды. Эпос'};
- {Code='antique'; Text='Старинная литература: Прочее'}
- }
- };
- {Text='Научно-образовательная';
- Sub={
- {Code='sci_history'; Text='История'};
- {Code='sci_psychology'; Text='Психология'};
- {Code='sci_culture'; Text='Культурология'};
- {Code='sci_religion'; Text='Религиоведение'};
- {Code='sci_philosophy'; Text='Философия'};
- {Code='sci_politics'; Text='Политика'};
- {Code='sci_juris'; Text='Юриспруденция'};
- {Code='sci_linguistic'; Text='Языкознание'};
- {Code='sci_medicine'; Text='Медицина'};
- {Code='sci_phys'; Text='Физика'};
- {Code='sci_math'; Text='Математика'};
- {Code='sci_chem'; Text='Химия'};
- {Code='sci_biology'; Text='Биология'};
- {Code='sci_tech'; Text='Технические'};
- {Code='science'; Text='Научно-образовательная: Прочее'};
- {Code='adv_animal'; Text='Природа и Животные'};
- }
- };
- {Text='Компьютеры и Интернет';
- Sub={
- {Code='comp_www'; Text='Интернет'};
- {Code='comp_programming'; Text='Программирование'};
- {Code='comp_hard'; Text='Компьютерное Железо'};
- {Code='comp_soft'; Text='Программы'};
- {Code='comp_db'; Text='Базы данных'};
- {Code='comp_osnet'; Text='ОС и Сети'};
- {Code='computers'; Text='Компьютеры и Интернет: Прочее'}
- }
- };
- {Text='Справочная литература';
- Sub={
- {Code='ref_encyc'; Text='Энциклопедии'};
- {Code='ref_dict'; Text='Словари'};
- {Code='ref_ref'; Text='Справочники'};
- {Code='ref_guide'; Text='Путеводители'};
- {Code='reference'; Text='Справочная литература: Прочее'}
- }
- };
- {Text='Документальное';
- Sub={
- {Code='nonf_biography'; Text='Биографии и Мемуары'};
- {Code='nonf_publicism'; Text='Публицистика'};
- {Code='nonf_criticism'; Text='Критика'};
- {Code='nonfiction'; Text='Документальное: Прочее'};
- {Code='design'; Text='Искусство'};
- {Code='adv_animal'; Text='Природа и Животные'}
- }
- };
- {Text='Религия и Духовность';
- Sub={
- {Code='religion_rel'; Text='Религия'};
- {Code='religion_esoterics'; Text='Эзотерика'};
- {Code='religion_self'; Text='Самосовершенствование'};
- {Code='religion'; Text='Религия и духовность: Прочее'};
- {Code='sci_religion'; Text='Религиозное образование'}
- }
- };
- {Text='Юмор';
- Sub={
- {Code='humor_anecdote'; Text='Анекдоты'};
- {Code='humor_prose'; Text='Юмористическая проза'};
- {Code='humor_verse'; Text='Юмористические стихи'};
- {Code='humor'; Text='Юмор: Прочее'}
- }
- };
- {Text='Дом и Семья';
- Sub={
- {Code='home_cooking'; Text='Кулинария'};
- {Code='home_pets'; Text='Домашние животные'};
- {Code='home_crafts'; Text='Хобби и Ремесла'};
- {Code='home_entertain'; Text='Развлечения'};
- {Code='home_health'; Text='Здоровье'};
- {Code='home_garden'; Text='Сад и Огород'};
- {Code='home_diy'; Text='Самоделки'};
- {Code='home_sport'; Text='Спорт'};
- {Code='home_sex'; Text='Эротика и Секс'};
- {Code='home'; Text='Дом и Семья: Прочее'};
- {Code='geo_guides'; Text='ГеоПутеводитель'}
- }
- };
- {Text='Экономика, Бизнес';
- Sub={
- {Code='job_hunting'; Text='Поиск работы, карьера'};
- {Code='management'; Text='Управление, подбор персонала'};
- {Code='marketing'; Text='Маркетинг, PR, реклама'};
- {Code='banking'; Text='Банковское дело'};
- {Code='stock'; Text='Ценные бумаги, инвестиции'};
- {Code='accounting'; Text='Бухучет, налогообложение, аудит'};
- {Code='global_economy'; Text='Внешнеэкономическая деятельность'};
- {Code='economics'; Text='Экономика'};
- {Code='industries'; Text='Отраслевые издания'};
- {Code='org_behavior'; Text='Корпоративная культура'};
- {Code='personal_finance'; Text='Личные финансы'};
- {Code='real_estate'; Text='Real Недвижимость'};
- {Code='popular_business'; Text='О бизнесе популярно'};
- {Code='small_business'; Text='Малый бизнес'};
- {Code='paper_work'; Text='Paper Делопроизводство'};
- {Code='economics_ref Справочники'}
- }
- };
- }
- local function OEMtoUTF_8(str)
- return win.WideCharToMultiByte(win.MultiByteToWideChar(str, win.GetOEMCP()), 65001)
- end
- local function AddLine(Line, hOut)
- --editor.InsertString()
- --editor.SetString(nil, Editor.Lines-1, Line, CR_LF)
- hOut:write(( Line:match('^(.-)%s*$') or Line)..CR_LF)
- end
- local ampsims={
- ['\'']=''';
- ['"']='"';
- ['&']='&';
- ['<']='<';
- ['>']='>';
- ['©']='©';
- ['®']='®';
- }
- local function ToAmp(Str)
- -- Замена символов на &-последовательности
- local r=''
- local iPos
- repeat
- --iPos = unicode.utf8.cfind(Str, '[&\'"$<>©®]')
- iPos = Str:cfind('[&\'"$<>©®]')
- if iPos then
- r = r .. Str:sub(1,iPos-1) .. ampsims[Str:sub(iPos,iPos)]
- Str = Str:sub(iPos+1)
- end
- until not iPos
- if Str ~= '' then
- r = r .. Str
- end
- return r
- end
- local function _txt2fb2(fn, CanQuit)
- Far.DisableHistory(1)
- local DlgItems, ID, y = {}, {}
- local DlgGUID = win.Uuid('8071F9E9-8E86-415E-B2F8-6901B187E374')
- local DlgResult
- tin(DlgItems, { "DI_DOUBLEBOX", 0, 0, 73, 15, 0, 0, 0, 0, 'Преобразование '..fn..' в FB2' })
- y = 1
- tin(DlgItems, {'DI_TEXT',3,y,0,y,0,0,0,0,"Жанр"})
- y= y + 1
- tin(DlgItems, {'DI_COMBOBOX', 3,y,27,y, GenreList,0,0,{DIF_DROPDOWNLIST=1;DIF_CENTERGROUP=1}})
- ID.Genre=#DlgItems
- tin(DlgItems, {'DI_COMBOBOX', 30,y,68,y, GenreList[1].Sub,0,0,{DIF_DROPDOWNLIST=1;DIF_CENTERGROUP=1}})
- ID.SubGenre=#DlgItems
- y = y + 2
- tin(DlgItems, {"DI_TEXT", 3,y,0,y,0,0,0,0,"Данные автора:"})
- y = y + 1
- tin(DlgItems, {"DI_TEXT", 3,y,0,y,0,0,0,0,"имя"})
- tin(DlgItems, {"DI_EDIT", 7,y,33,y,0,'Txt2FB.AuName',0,{DIF_SELECTONENTRY=1; DIF_HISTORY=1;DIF_USELASTHISTORY=1}})
- ID.AuName=#DlgItems
- tin(DlgItems, {"DI_TEXT", 35,y,0,y,0,0,0,0,"фамилия"})
- tin(DlgItems, {"DI_EDIT", 43,y,68,y,0,'Txt2FB.AuFam',0,{DIF_SELECTONENTRY=1; DIF_HISTORY=1;DIF_USELASTHISTORY=1}})
- ID.AuFam=#DlgItems
- y = y + 2
- tin(DlgItems, {"DI_TEXT", 3,y,0,y,0,0,0,0,"Серия"})
- tin(DlgItems, {"DI_EDIT", 9,y,60,y,0,'Txt2FB.Seq_Name',0,{DIF_SELECTONENTRY=1;DIF_HISTORY=1;DIF_USELASTHISTORY=1}})
- ID.Seq_Name=#DlgItems
- tin(DlgItems, {"DI_TEXT", 63,y,0,y,0,0,0,0,"№"})
- tin(DlgItems, {"DI_EDIT", 65,y,68,y,0,0,0,{DIF_SELECTONENTRY=1}})
- ID.Seq_Number=#DlgItems
- y = y + 1
- tin(DlgItems, {"DI_TEXT", -1,y,0,y,0,0,0,{DIF_SEPARATOR=1}})
- y = y + 1
- tin(DlgItems, {"DI_TEXT", 3,y,0,y,0,0,0,0, "Название книги"})
- y = y + 1
- tin(DlgItems, {"DI_EDIT", 3,y,65,y,0,0,0,{DIF_SELECTONENTRY=1}})
- ID.Title=#DlgItems
- y = y + 1
- tin(DlgItems, {"DI_TEXT", 3,y,0,y,0,0,0,0, "Аннотация"})
- y = y + 1
- tin(DlgItems, {"DI_FIXEDIT", 3,y,68,y,0,0,0,{DIF_EDITOR=1}})
- ID.Ann_1=#DlgItems
- y = y + 1
- tin(DlgItems, {"DI_FIXEDIT", 3,y,68,y,0,0,0,{DIF_EDITOR=1}})
- y = y + 1
- tin(DlgItems, {"DI_FIXEDIT", 3,y,68,y,0,0,0,{DIF_EDITOR=1}})
- y = y + 1
- tin(DlgItems, {"DI_EDIT", 3,y,68,y,0,0,0,{DIF_EDITOR=1}})
- ID.Ann_2=#DlgItems
- y = y + 2
- tin(DlgItems, {"DI_BUTTON", 0,y,0,y,0,0,0,{DIF_CENTERGROUP=1; DIF_DEFAULTBUTTON=1},"Ок"})
- ID.OkBtn=#DlgItems
- tin(DlgItems, {"DI_BUTTON", 0,y,0,y,0,0,0,{DIF_CENTERGROUP=1},"Cancel"})
- ID.CancelBtn=#DlgItems
- if CanQuit then
- tin(DlgItems, {"DI_BUTTON", 0,y,0,y,0,0,0,{DIF_CENTERGROUP=1},"&Quit"})
- ID.QuitBtn=#DlgItems
- end
- local function _DlgProc(hDlg, Msg, ItemId, Param2)
- if Msg == F.DN_INITDIALOG then
- hDlg:send("DM_LISTSETCURPOS", ID.Genre, {SelectPos=1; TopPos=1})
- hDlg:send("DM_LISTSETCURPOS", ID.SubGenre, {SelectPos=1})
- elseif Msg == F.DN_DROPDOWNOPENED and
- ItemId == ID.Genre and
- Param2 == 0 then
- hDlg:send( "DM_LISTSET", ID.SubGenre, GenreList[hDlg:send("DM_LISTGETCURPOS", ID.Genre).SelectPos].Sub )
- hDlg:send("DM_LISTSETCURPOS", ID.SubGenre, {SelectPos=1})
- elseif Msg == F.DN_CLOSE then
- if ItemId < 0 or ItemId == ID.CancelBtn or ItemId == ID.QuitBtn then
- DlgResult = nil
- bQuit = ItemId == ID.QuitBtn
- else
- DlgResult = {}
- local i1, i2 = hDlg:send("DM_LISTGETCURPOS", ID.Genre).SelectPos,
- hDlg:send("DM_LISTGETCURPOS", ID.SubGenre).SelectPos
- DlgResult.Genre = GenreList[i1].Sub[i2].Code
- DlgResult.AuName = hDlg:send("DM_GETTEXT", ID.AuName)
- DlgResult.AuFam = hDlg:send("DM_GETTEXT", ID.AuFam)
- DlgResult.Title = hDlg:send("DM_GETTEXT", ID.Title)
- DlgResult.Seq_Name = hDlg:send("DM_GETTEXT", ID.Seq_Name)
- DlgResult.Seq_Number = hDlg:send("DM_GETTEXT", ID.Seq_Number)
- local s=''
- for i=ID.Ann_1,ID.Ann_2 do
- s = s .. mf.trim(hDlg:send("DM_GETTEXT", i)) .. ' '
- end
- DlgResult.Annotation = mf.trim(s)
- if mf.trim(DlgResult.AuName or '') == '' or
- mf.trim(DlgResult.AuFam or '') == '' then
- far.Message('Необходимо указать имя и фамилию автора!','Не заполнены обязательные поля',';Ok','w')
- hDlg:send("DM_SETFOCUS", mf.trim(DlgResult.AuName or '') == '' and ID.AuName or ID.AuFam)
- return false
- end
- end
- end
- end -- _DlgProc
- DlgItems[1][5] = y+1
- far.Dialog(DlgGUID,-1,5,73,6+y, nil, DlgItems, "FDLG_SMALLDIALOG", _DlgProc)
- if not DlgResult then return end
- local fnOut= (Area.Shell and APanel.Path .. '\\' or '') .. mf.fsplit(fn, 7)..'.fb2'
- if mf.fexist(fnOut) then
- if far.Message('Файл '..fnOut..' существует.\nПереписать?',
- 'Создание файла fb2', ';YesNo', 'w') == 1 then
- win.DeleteFile(fnOut)
- else
- return false
- end
- end
- local hOut, msg=io.open(fnOut, 'w')
- if not hOut then
- far.Message('Неудача создания файла\n'..fnOut..'\n'..msg,'txt -> fb2', nil, 'w' )
- return false
- end
- for _,Line in ipairs(blank) do
- for w in Line:gmatch('#([%w_]+)#') do
- Line = Line:gsub('#'..w..'#', ToAmp(DlgResult[w] or '') )
- end
- AddLine(Line, hOut)
- if mf.trim(Line) == '<section>' then
- local iEmpL, sOut=0, ''
- local function AddLine1(Line1, ii)
- if Line1:match('%S') then -- прочитана непустая строка
- if Line1:match('^%s+') then -- строка начинается с пробелов (начало абзаца)
- if iEmpL > 1 then -- был разделитель - выталкиваю
- AddLine('<p><subtitle>* * *</subtitle></p>', hOut)
- end
- iEmpL = 0
- if sOut:match('%S') then -- Уже была сформирована непустая строка - выталкиваю
- AddLine('<p>'..ToAmp(sOut:match('^%s*(.*%S)%s*$'):gsub('%s+',' '))..'</p>', hOut)
- sOut = ''
- end
- elseif iEmpL > 0 then
- -- Строка начинается не с пробелов, но ей предшествует пустая - тоже абзац
- if sOut:match('%S') then
- AddLine('<p> '..ToAmp(sOut:match('^%s*(.*%S)%s*$'):gsub('%s+',' '))..'</p>', hOut)
- sOut = ''
- end
- iEmpL = 0
- end -- Line1 - непустая
- local function _ItIsHdr(L)
- local l1,l2, l3=L:match('^(%s+)(.-)(%s+)$')
- return l1 and l2 and l3 and l2:match('^[%d%u][%d%u.%s -/]+$') and (math.abs(l1:len()-l3:len()) <= 2)
- end
- if _ItIsHdr(Line1) then
- if sOut:match('%S') then
- AddLine(sOut, hOut)
- sOut = ''
- end
- AddLine('</section><section><title><p>'..Line1..'</p></title>', hOut)
- else
- sOut = sOut .. Line1 .. ' '
- end
- else -- пустая строка; подсчитываю колиичество
- iEmpL = iEmpL + 1
- end
- end -- function AddLine1
- far.Message('Создание\n'..mf.fsplit(fnOut, 12),'','')
- local aLines={}
- if Area.Editor then
- for i=1,Editor.Lines do
- aLines[i] = Editor.GetStr(i)
- end
- else
- for ll in io.lines(fn) do
- aLines[#aLines+1] = OEMtoUTF_8(ll):gsub('[\1-\31]+', ' ')
- end
- end
- -- Вычисление правой границы
- local rb=0
- for _, Line1 in ipairs(aLines) do
- rb = math.max(rb,Line1:len())
- end
- for ii, Line1 in ipairs(aLines) do
- AddLine1(mf.strpad(Line1, rb), ii )
- end -- for Line1 in io.lines(...)
- if sOut:match('%S') then
- AddLine('<p>'..sOut:match('^%s*(.*%S)%s*$'):gsub('%s+',' ')..'</p>', hOut)
- end
- far.AdvControl("ACTL_REDRAWALL")
- end
- end
- hOut:close()
- end -- _txt2fb2
- local function txt2fb2()
- local PanItem
- local aFn={}
- bQuit = false
- if APanel.Selected then
- for i=1,APanel.SelCount do
- PanItem = panel.GetSelectedPanelItem(nil, 1, i)
- if not PanItem.FileAttributes:match('d') and
- far.ProcessName("PN_CMPNAME", '*.txt', PanItem.FileName) then
- tin(aFn, PanItem.FileName)
- end
- end
- for i,v in ipairs(aFn) do
- _txt2fb2(v, i<#aFn)
- if bQuit then break end
- end
- else
- _txt2fb2(APanel.Current, false)
- end
- end
- --------------------------------------------------
- Macro{
- -- id="";
- area="Shell";
- key="CtrlShiftB-F";
- description="F - Преобразование txt в fb2";
- -- filemask="";
- flags="";
- -- priority=50;
- -- sortpriority=50;
- condition=function(_)
- local bRes=false
- if APanel.Selected then
- local PanItem
- for i=1,APanel.SelCount do
- PanItem = panel.GetSelectedPanelItem(nil, 1, i)
- if not PanItem.FileAttributes:match('d') and
- far.ProcessName("PN_CMPNAME", '*.txt', PanItem.FileName) then
- bRes = true
- break
- end
- end
- else
- bRes = (not APanel.Folder and far.ProcessName("PN_CMPNAME", '*.txt', APanel.Current) )
- end
- if bRes then
- dtLast = 0
- else
- if dtLast == 0 then
- dtLast = os.time()
- elseif os.time()-dtLast < 10 then
- dtLast = 0 --os.time()
- far.Message('Необходимо либо установить указатель на файл *.txt,\nлибо отметить хотя бы один такой файл',
- 'Ошибка вызова процедуры', ';Ok', 'w')
- end
- end
- return bRes
- end;
- action=function()
- txt2fb2()
- end;
- }
- Macro{
- -- id="";
- area="Editor";
- key="CtrlShiftB-F";
- description="F - Преобразование txt в fb2";
- filemask="*.txt";
- flags="";
- -- priority=50;
- -- sortpriority=50;
- -- condition=function(key) return true end;
- action=function()
- _txt2fb2(Editor.FileName, false)
- end;
- }
GeSHi © Codebox Plus Extension
Плюсы:
- Не требуется установка fb2-редактора (например, FictionBook Editor);
- Разбивает форматированный текстовый файл на параграфы (началом параграфа считается строка, начинающаяся с пробелов; две и более пустые строки заменяются на разделитель * * *)
- Можно указать только одного автора
- Не предусмотрен ввод отчества
- Можно указать только один жанр и только одну серию
- Не реализован ввод картинок (в т.ч. и обложки)
- Не реализованы некоторые другие теги форматирования (poem, подпись автора и т.п.). Ну и вообще - там всё так автоматизировано, что для наведения красоты пользуйтесь "серьёзным" софтом
Т.к. несколько человек скачали (и парочка даже поблагодарили ), решил подправить некоторые недочёты.
- Добавлена возможность распознавать заголовки глав, частей и т.п. . Признаком, что строка является заглавием, является (а) примерно (с разницей не более 2) одинаковое количество ведущих и концевых пробелов и (б) написание всей строки заглавными буквами. Ограничение: распознаются только однострочные заголовки
- Исправлена ошибка, из-за которой макрос был чувствителен к регистру имени файла
- Сделана обработка отмеченных файлов
- Сделана история (чтобы при обработке книг одного автора не приходилось каждый раз вводить его имя/фамилию)
- Сделана замена символов типа '<', '>', '"', '&' и т.п. на &-последовательности, как это требует стандарт xml
"Защита от дурака" по некоторым моментам (например, файл fb2 существует; запись в папку запрещена и т.п.) не реализована. Если кто-нибудь заинтересуется - пишите, доделаю...
В макросе создание "повешено" на сочетание CtrlShiftB-F, что предполагает наличие макроса, позволяющего вводить "сложные" сочетания клавиш. Настройка не предусмотрена.
Работоспособность макроса проверена чтением результата программой Cool Reader 2
- txt2fb2.lua.7z
- txt2fb2.lua, Версия 3
- (5.85 KiB) Downloaded 91 times