Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Сб июл 02, 2022 12:08

...
Google Search
Forth-FAQ Spy Grafic

Часовой пояс: UTC + 3 часа [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 6 ] 
Автор Сообщение
 Заголовок сообщения: Расформатирование текста
СообщениеДобавлено: Пт май 11, 2007 00:32 
Замечание: ТЗ заранее в этой задаче описать нереально, так как задача эта пусть и небольшая, но всё-таки "из этой жизни". Даже входные и выходные данные не поддаются никакой категоризации в виду почти бесконечного их разнообразия (читая дальше, вы это увидите). Тем не менее, задача решаема, и решаема через достаточно краткие алгоритмы и программы.

С форматированием по ширине как-то разобралися. Не такая и простенькая как кажется сначала задачка. А эта задача является в какой-то мере обратной первой и звучит кратко и "просто":

Мы получили отформатированный plain-text. Восстановите "исходный материал" из plain-text, выцепив из него как можно больше оформления.

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

Под "восстановлением его обратно" понимается приведение текста к виду "одна строка -- один абзац".

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

1. Пустые строки между абзацами. Они могут быть, а могут и не быть.
2. Заголовки. Они могут быть отбиты пробелами. Перед ними (после них) могут стоять пустые строки. А могут и не стоять.
3. Часто делают такие разрывы разделов в виде горизонтальных чёрточек в тексте: "----------"
3. Цитаты и эпиграфы. Аналогично.
4. "Красная строка" абзаца. Опять же, её может и не быть.
5. Переносы слов.

(и это ещё я не прошу правильно обрабатывать псевдографику, таблицы, номера страниц с колонтитулами и сноски)..

За примерами "форматированных текстов" далеко ходить не надо: зайдите на тот же lib.ru и скачайте пару текстов в формате 'plain text'. Но могу предоставить и тех же кошек на которых тренировал некогда своего питомца:

Дуглас Адамс "Всего хорошего, и спасибо за рыбу!" (7-Zip, 105 Кб)
Роберт Асприн "Другой отличный миф" (7-Zip, 114 Кб)


Покажем примерный образец входного текста:

Код:
                             РОБЕРТ АСПРИН

                          ДРУГОЙ ОТЛИЧНЫЙ МИФ


     Эта  книга  посвящается  Борку  Неуничтожимому  (известному меньшим
смертным как Джордж Хант), чья грубоватая, но верная дружба помогла  мне
преодолеть много кризисов в прошлом... и, вероятно, в будущем!



                                ГЛАВА 1

"Есть  многое  на  свете,                         
друг Горацио, что чело-                         
веку знать не положено"                           
                                                   

                                                           
Есть многое на свете,
друг Горацио,
что и не снилось
нашим мудрецам.
     Гамлет.

     Одно  из  немногих  все искупляющих качеств  наставников,  думаю я,
заключается в том,  что их при  случае можно одурачить.  Это было верно,
когда  мать  учила  меня  читать,  это  было  верно,  когда отец пытался
научить меня быть фермером, и верно теперь, когда я обучаюсь магии.
     -  Ты  не  практиковался!  -  прервал  мои размышления резкий упрек
Гаркина.
     - А вот и нет! - возразил я.- Это просто трудное упражнение.


[аттракцион невиданного тщеславия]
Чтобы дать ориентир скажу что с задачей этой я столкнулся лет пять назад и решал её несколькими разными алгоритмами и на нескольких языках в течении нескольких лет. Наиболее удобным решением в конце концов стала для меня программка (8 Кб обильно комментированных исходников в виде одного файла, 50 Кб исполняемого модуля) которая умела: правильно обрабатывать две кодировки (ANSI и OEM -- KOI в художественных текстах был редок); распознавать абзацы, учитывая пункты, указанных выше; распознавать и оформлять заголовки (при этом, в сомнительных случаях, когда заголовки не отбивались пробелами для центровки, программа брала на вооружение некоторую "эвристику", автоматом считая короткие абзацы начинающиеся со "Глава" или "Часть" -- заголовками, а также обращая внимание на то что все буквы в строке -- большие); распознавать чёрточки-разделители, как заголовки; учитывать "красные строки"; учитывать и оформлять переносы строк (в выходном документе эти переносы делались "мягкими"); делать дополнительные типографские уснащения в виде распознавания тире (отдельно от дефисов и минусов!), многоточий и кавычек; при этом на выходе получался файл с расширением doc, который если открыть в Word'е, можно было сразу печатать, так как у него уже было наложено оформление для плотной печати в виде альбомной ориентации, узких полей страницы, трёх колонок, мелкого шрифта, и установки что Word сам должен правильно проставить в трёх колонках переносы слов.
[/аттракцион невиданного тщеславия]

Я понимаю что задача достаточно масштабная (прежде всего из-за почти незакреплённого и очень "человеческого" входного формата), но, как решения сойдут и программы, просто отделяющие один абзац от другого. Выделение заголовков, цитат и эпиграфов -- это уж вам как время и задор позволят.

Выходной формат не закрепляется, хотя наиболее удобным будет наверное, или HTML, если захотитет делать оформля ть больше чем просто абзацы. Если вам удобней будет скажем RTF -- это на самом деле неважно. Или можно форматировать в какую-нибудь вику-разметку или даже bbcode -- не суть важно. Если же обходимся простыми абзацами то тот же plain-text в формате "один абзац -- одна строка" вполне подойдёт.

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

Изображение

Задача эта взята из жизни исключительно и озадачивались ей многие. Например, есть программа ClearTXT. Или в библиотеке Мошкова есть скрипты на Perl'е (кажется) для обработки книг заданных с оформлением в тексте.

Повторюсь -- напрягаться сильно не надо. Просто распознавания абзацов должно хватить, а там посмотрим.


Вернуться к началу
  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 14:20 
Код:
\ SPF4.18 gl0
\ расформатирование текста
STARTLOG
lib/ext/locals.f
\ преобразование формата
: a-au ( adr -- adr u )
   DUP 4 + SWAP @ ;

\ создание строки 
: crtstr ( u -- adr )
   4 + ALLOCATE THROW DUP 0 SWAP ! ;
\ прибавить к строке строку
: str+ ( adr adr1 u1 -- adr )
   { adr adr1 u1 }
   adr DUP @ 4 + u1 + RESIZE THROW -> adr
   adr DUP @ 4 + + adr1 SWAP u1 MOVE
   adr @ u1 + adr ! adr ;
   
\ полученую входную строку переводем в область динамически выделеной памяти \ первые 4 байта содержат длину строки
: in_str ( adr u -- adr )
   DUP 4 + ALLOCATE THROW 2DUP ! DUP >R 4 + SWAP MOVE R> ;

\ посчитать от adr u входной строки, u1 последовательность повторяющихся символов
: get_s ( adr u -- c u1 )
   { adr u \ k }
   BEGIN
   k 1+ -> k adr C@ adr k + C@ <> k u = +
   UNTIL
   adr C@ k u MIN ;
   
\ в указаной области заменить групы символов "С" если их находиться подряд более k
\ группами символов "С" длинной i
: c_k-i ( adr c k i -- adr )
   { adr c k i \ adr1 u1 r }
   0 -> u1
   BEGIN
   adr @ DUP u1 <> *
   WHILE
   adr 4 + u1 + adr @ u1 - get_s
   DUP -> r k > >R c = R> *
     IF    \ искомое условие
     0 crtstr
     adr 4 +          u1 1 +         str+
     adr 4 + u1 + r + adr @ u1 - r - str+
     adr FREE THROW -> adr
     THEN
     u1 1+ -> u1
   REPEAT adr ;
   
\ в тексте adr заменить строки adr1 u1 на строку adr2 u2 
: chnstr ( adr adr1 u1 adr2 u2 -- adr )
   { adr adr1 u1 adr2 u2 \ u3 r }
   0 -> u3
   BEGIN
   adr @ DUP u3 <>  *
   WHILE
   adr 4 + u3 + u1 adr1 u1 COMPARE 0=
     IF   \ найдено совпадение
     0 crtstr
     adr 4 + u3 str+
     adr2 u2    str+
     u3 u1 + DUP adr @ SWAP - SWAP adr 4 + + SWAP str+
     adr FREE THROW -> adr
     u2 u1 >
       IF
       u3 u2 + 1- -> u3
       ELSE
       -1 -> u3
       THEN
     THEN
     u3 1+ -> u3
   REPEAT
   adr
;
 
0x0A0D VALUE _end
 
\ одиночный перевод строки
: end       ( -- adr u ) S" ad"    OVER _end SWAP W! ;
\ двойной переод строки
: 2end      ( -- adr u ) S"     "  OVER _end SWAP W! OVER _end SWAP 2 + W! ;
\ перевод строки и пробел
: end_bl    ( -- adr u ) S" adb"   OVER _end SWAP W! OVER BL SWAP 2 + C! ;
\ абзац
: end_tab  ( -- adr u ) S" AD "    OVER _end SWAP W! OVER 2 + 9 SWAP C! ;
 
\ добавить первый абзац 
: ftab+ ( adr -- adr )
   { adr }
   0 crtstr S"  " str+ adr a-au str+
   adr FREE THROW -> adr 9 adr 4 + C! adr ;
 
\ удалить первый пробел
: fbl- ( adr -- adr )
   { adr }
   adr 4 + C@ BL =
   IF
   0 crtstr adr a-au 1- SWAP 1+ SWAP str+ -> adr
   THEN adr ;
 
\ удалить последние пробелы и переводы строк
: ebl- ( adr -- adr )
   { adr }
   BEGIN
   adr a-au + 1- C@ BL   =
   adr a-au + 1- C@ 0x0A = +
   adr a-au + 1- C@ 0x0D = +
   adr a-au + 1- C@ 9    = +
   WHILE
   0 crtstr adr a-au 1- str+ 
   adr FREE THROW -> adr
   REPEAT adr
;
 
\ считать файл, adr u - имя файла adr1 - строка с текстом файла
: in_fl ( adr u -- adr1 )
   { \ hndl adr u }
   R/O OPEN-FILE THROW -> hndl
   hndl FILE-SIZE THROW D>S -> u
   u 4 + ALLOCATE THROW -> adr
   adr 4 + u hndl READ-FILE THROW DROP
   hndl CLOSE-FILE THROW
   u adr ! adr
;

\ TEST
\ чистка, adr1 u1 - имя файла, adr u - итоговый текст
: test ( adr1 u1 -- adr u )
   { \ adr }
   in_fl
   32 1 1  c_k-i                        \ групы пробелов боле одного перобразуються в одиночный
   end_bl end chnstr 2end end chnstr    \ удаляем пустые строки
   end end_tab chnstr                   \ установить абзацы
   fbl-                                 \ удалить первые пробел если есть
   ftab+                                \ добавить первый абзац
   ebl-                                 \ удаляем последние переводы строк и пробелы и абзацы
   -> adr
   adr
;

при необходимости удалить например раздиления вида " --------------- "
можно добавить после "32 1 1 c_k-i "
45 2 0 c_k-i \ это означаит преобразовать все групы тире в количестве более двух в количество около нуля


Вернуться к началу
  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 14:28 
не бейте шибко , просто спешил закончить потом некогда будет , юбилеи, базы,
Код:
: test ( adr1 u1 -- adr u )
   { \ adr }
   in_fl
   32 1 1  c_k-i                        \ групы пробелов боле одного перобразуються в одиночный
   end_bl end chnstr 2end end chnstr    \ удаляем пустые строки
   end end_tab chnstr                   \ установить абзацы
   fbl-                                 \ удалить первые пробел если есть
   ftab+                                \ добавить первый абзац
   ebl-                                 \ удаляем последние переводы строк и пробелы и абзацы
   -> adr
   adr a-au
;


Вернуться к началу
  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 14:38 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
mrack_ писал(а):
это означаит преобразовать все групы тире в количестве более двух в количество около нуля


Надо заметить, что в некоторых текстах используется двойное и тройное тире, как обозначение
соответствующих символов (смотреть в сторону LaTeX). т.е. проверка для тире должна быть не
сильно тупой.

_________________
С уважением, WingLion
Forth-CPU . RuF09WE
Мой Форт
Отсутствие бана это не заслуга юзера, а недоработка модератора (с)


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 20:45 
Не в сети
Аватара пользователя

Зарегистрирован: Пт май 05, 2006 06:19
Сообщения: 192
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
WingLion ну так это относиться к пункту
profiT писал(а):
Замечание: ТЗ заранее в этой задаче описать нереально, так как задача эта пусть и небольшая, но всё-таки "из этой жизни". Даже входные и выходные данные не поддаются никакой категоризации в виду почти бесконечного их разнообразия (читая дальше, вы это увидите). Тем не менее, задача решаема, и решаема через достаточно краткие алгоритмы и программы.

из начально решение и предполагало гибкость хош оставить и по три тире пишем: "45 3 0 c_k-i" и удаляем только те кто больше трех
считаеш три перебором "45 3 0 c_k-i 45 2 2 c_k-i " удаляем все что больше трех тире, а те что по три переделываем в по два,

_________________
SPF


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 22:02 
Не в сети
Аватара пользователя

Зарегистрирован: Пт май 05, 2006 06:19
Сообщения: 192
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Код:
\ TEST
: end_3bl
   S" ad   " OVER _end SWAP W! ;
   
\ чистка, adr1 u1 - имя файла, adr u - итоговый текст
: test ( adr1 u1 -- adr u )
   { \ adr }
   in_fl
   end_3bl S" |||||" chnstr
   end S"  " chnstr
   S" |||||" end_tab chnstr
   32 1 1 c_k-i
   -> adr
   adr
;
0 VALUE str
0 VALUE hn
S" adams4.txt" test TO str
S" out.txt" W/O CREATE-FILE THROW TO hn
str a-au hn WRITE-FILE THROW
hn CLOSE-FILE THROW
CR S" OK == " TYPE 

секция тест для adams4.txt , на целероне 1500 работает ~45 секунд основной отъем времени идет в "chnstr" так как прикаждой замене большей части в тексте на меньшую начинает поиск с начала, хотя наверно это стоит оставить только для режима удаления части текста. время сильно сократиться,
а может и нет, так как искомые шаблоны для модификации могут появляться при вставке, но тогда можно вообще сесть в ситуацию:например папытка заменить в тексте фрагмент "такойто" на "такойто и такойто" приведет к зацикливанию.
ну и потенциальный глюк с подменой "перевод строки три пробела" (собсно обзац) на "|||||" если в тексте гденить используеться такой текст то там появиться абзац

_________________
SPF


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 6 ] 

Часовой пояс: UTC + 3 часа [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
phpBB сборка от FladeX // Русская поддержка phpBB