Все видели просмотрщик html-файлов в TotalCommander. Загорелся идеей написать простой и очень маленький текстовый браузер для своей операционки. Поначалу, смотрел в сторону asm-xml — отличный парсер, однако ну очень уж большой (мой предел — 64 килобайта, не технический, просто принцип такой). Ниже описан очень простой способ получения текста из html.
Сразу оговорюсь, что код мне нужен именно независимый, (для своей ОС), поэтому все готовые библиотеки отпадают сразу. Почему assembler? — только потому что всё в моей ОС пишется на нем. Но метод можно передвинуть на любой язык…
Итак, поскольку важен маленький размер кода — от классического парсера с построением дерева, парсингом иерархической структуры решил отказаться. Пошел «в лоб».
Собственно, процесс состоит из нескольких этапов.
Вначале нужно избавиться от содержимого тегов script — только тех, где код написан напрямую, а не там, где подключаются внешние скрипты. Почему? Просто дошел опытным путем, когда выявил, что некоторые, весьма большие, скрипты ломают логику моего парсера)
Далее идет основной цикл. Мы шаг за шагом (точнее байт за байтом) проходим все теги (ищем открытие и закрытие тега). Т.е. у нас в итоге получается не дерево тегов, а список, состоящий из строк преполненных dword заголовками.
Если текст не подпадает под тег — то и записываем его просто как текст.
Структура временная выглядит так (касным выделены заголовки — обозначение тегов):
Поясню момент. Казалось бы, логичнее каждому тегу выдать соответствующий хеш или идентификатор. Но, для этого нужно парсить все виды тегов, например: <p и <p style=… — нужно отдельно проверять. А у нас же — просто проход до файлу со сравнением через каждый байт четырех байт:
inc esi
cmp byte[esi + 0], '<'
Если это открывающий тег, то <p class… превращаем в :p:
Это, конечно же, лентяйство, говнокод и т.п., но это быстро, коротко и эффективно!
Ну а дальше собственно берем получившийся список и строка за строкой, в зависимости от типа тега, отдаем на обработку соответствующей процедуре обработки, которая пишет уже в выходной буфер. (Есть еще мелочи эстетические — убираем повторение пробелов, переносов и т.п.)
Ожидаю комментариев вида: «говнокод», «учи матчасть» и т.п. Поэтому скажу сразу: код (в конце статьи ссылка) — это просто прототип, написанный «на коленке», а насчет «алгоритма» — согласен, это трудно назвать алгоритмом, но он работает! Всего 4Кб программа!
По ссылке рабочий пример (проверял также на исходнике html главной страницы хабра — скрин внизу) — всё работает. Единственно — ограничение размера файла (просто пока не добавил выделение памяти, использую 3 по 64 Кб неинициализированных буфера). После работы программа выдаст два файла — в одном список временный, во втором — готовый текст. Учтите, что в тексте переносы — это 0x0A, поэтому смотрим TotalCommander'ом в режиме текста.
Тест на документе «W3C Reformulating HTML in XML»:
Тест на главной страницу Хабрахабра:
А теперь вопрос: у кого получится меньше, чем 4Кб?
Автор: omegicus