Практика регулярных выражений в 1С или парсим неудобные форматы
В продолжение статьи Использование регулярных выражений (RegExp) в 1С8.х. Углубляемся в практику использования регулярных выражений в 1С. Основы работы с регулярными выражениями хорошо описаны в указанной публикации. А я попробую ответить на вопрос "почему именно регулярные выражения?" на примере конкретной рабочей задачи.
- Описание
- Подробнее
Описание
В продолжение статьи Использование регулярных выражений (RegExp) в 1С8.х. Углубляемся в практику использования регулярных выражений в 1С. Основы работы с регулярными выражениями хорошо описаны в указанной публикации. А я попробую ответить на вопрос «почему именно регулярные выражения?» на примере конкретной рабочей задачи.
Удобный и неудобный
Прежде чем приступить к непосредственному разбору практической задачи хотелось бы внести ясность в понятия «удобный» и «неудобный» формат на примере xml и html. Первый (xml — расширяемый язык разметки) предназначен именно для хранения информации, в то время как последний (html — язык разметки гипертекста) предназначен для структурированного отображения информации.
«В чем же такая большая разница? И там и там язык разметки.» — резонно заметите вы. Все дело в значимых тегах. Теги xml предназначены для идентификации определенного в них содержимого. Например:

Слово «Иванов», заключенное в тег для читающей xml-файл системы будет означать, что Иванов — автор, со всеми вытекающими последствиями. xml потому и называется «расширяемым», что названия тегов разработчик вводит сам с учетом потребностей по хранению/передаче определенной информации.
Теги html служат для того, чтобы сказать читающей системе (браузеру), как нужно визуализировать (отобразить в окне браузера) те или иные данные. Теги html конечны, т.е. разработчик сам не может придумать свой тег, иначе браузер его не поймет. Например:

Для браузера будет означать, что слово «Иванов» отображается в окне браузера как новый параграф с соответствующими отступами и т.п. Из этого мы вовсе не знаем, что Иванов — автор. Очевидно, что html — неудобный для парсинга (разбора) формат.
Справедливости ради надо заметить, что html может стать частично удобным форматом если тегам начать присваивать классы или идентификаторы. Если в нашем случае будет написано например так:

то в принципе из этого можно конечно заключить, что Иванов — автор, но все-таки это скорее ухищрение, т.к. классы в html естественно не предназначены для идентификации данных — они предназначены для конкретизации визуализации (отображения) и лишь косвенно могут служить для идентификации. Поэтому давайте считать html неудобным форматом для хранения/передачи информации.
Все было бы хорошо, НО на практике иногда приходится сталкиваться с задачами, когда данные нужно извлечь именно из таких вот неудобных форматов, как html. Приведу пример (который собственно дальше и разберу). У меня есть разработка Анализатор мобильной связи. Один из клиентов предоствил для извлечения детальных расходов по трафику именно html, в котором у тегов напрочь отсутствуют идентификаторы или классы, т.е. никакого намека на возможность идентификации. Однако не все потеряно, даже наоборот, все очень даже интересно получается с помощью регулярных выражений. Ведь html — это вовсе не набор бессвязной информации, а вполне себе структурированное содержимое, отдельные части которого имеют зависимости друг между другом.
Почему регулярные выражения?
Суть работы с регулярными выражениями сводится к элементарному разбору строк и поиску в них совпадений и субсовпадений. Прелесть метода последовательного построчного разбора очевидна — низкие требования к ресурсам компьютера.
«Почему именно регулярные выражения?» — сросите вы. Ведь можно использовать штатные средства платформы 1С «Найти», «СтрДлина», «СтрЗаменить» и пр. Да, можно, но программный код с использованием регулярных выражений локоничнее и понятнее. Для того, чтобы идентифицировать определенные данные в строке, нужно будет написать кучу «Если», «Найти», «СтрЗаменить» и т.д. В регулярных выражениях весь этот массив кода можно заменить одним шаблоном (паттерном).
Ключевым моментом при работе с регулярными выражениями является выявление уникальной комбинации строковых выражений. Именно комбинация определенных строковых выражений и служит идентификацирующим признаком значимых данных. Поясню. Например, встречая в разбираемом файле такую комбинацию тегов:

знаем, что в первом теге h1 содержится название автора произведения, во втором теге h2 содержится название произведения, а в третьем теге p содержится аннотация к произведению. Т.е. каждый раз встречая в файле набор этих тегов я заранее знаю что находится в первом, втором и третьем тегах. Повторюсь — здесь важно знать, что комбинация уникальна, т.е. не должно быть другой такой же комбинации тегов, в которых содержится какая-то другая информация или присутствует другой порядок данных. Это знание и регулярные выражения позволяют извлекать из таких вот уникальных комбинаций нужные данные.
Практика
Ничто так не позволяет усваивать материал, как практика.
Ниже на скриншоте вы можете наблюдать фрагмент отрисованного в браузере счета, присланного в формате html:

«Чудесно, это же всего-навсего таблица и распарсить ее не составит труда» — подумаете вы. Как бы не так. Не стоит забывать, что это всего лишь фрагмент, до и после которого есть уйма всякой сопутствующей информации, как-то разрывы строк, колонтитулы, итоги, заголовки страниц и пр. и пр., вобщем структурированный хаос информации. И такого хаоса мегабайт на 200.
А теперь вот как одна из строк выглядит в html коде (строка длинная, поэтому я сделал перенос строк и обозначил места переносов символом «|»):

Кто разбирается в HTML знает, что тег tr обозначает строку в таблице, а td обозначает колонку, точнее ячейку в определенной колонке определенной строки.
Парсить такое штатными средствами 1С весьма затруднительно, проще написать шаблон на языке регулярных выражений и текст исходного кода сокращается в разы. Ниже пример разбора в 1С такого кода с помощью регулярных выражений (обращаю внимание, что это лишь фрагмент кода и я не акцентирую внимание на создание в 1С объекта для работы с регулярными выражениями — это итак хорошо описано в обозначенной мной выше статье):

Это собственно весь разбор. Далее уже следует работа с извлеченными данными.
Если при разборе строки все условия регулярного выражения выполнены — это значит, что мы разбирали именно строку детализации, а значит в МассивеСовпадений располагаются в порядке очередности нужные данные (дата/время, номер собеседника, количество, стоимость и т.д.)
Давайте теперь пройдемся по регулярному выражению и переведем на русский язык условия, заданные с помощью самого него.

- Ищется тег td внутри которого может присутствовать описание классов, атрибутов и т.п.
- Ищется последовательность цифр и символов: 2 цифры, точка, 2 цифры, точка, 4 цифры, пробел, 2 цифры, двоеточие, 2 цифры, двоеточие, 2 цифры. Это ничто иное как дата и время. Причем все, что находится в круглых скобках запоминается и затем попадет в МассивСовпадений, за исключением тех скобок, в которых сначала идет ?:.
- Ищется закрывающий тег td, после которого идет произвольное количество тегов td до выполнения следующего по выражению условия.
- Далее по условию следует либо любой символ, кроме символа >, либо символ «пусто». Пусто, потому что в ячейке может быть пусто, что будет обозначено специальным символом. Здесь производится поиск номера собеседника.
- Далее по условию должны встретиться одна из букв F, D, S либо знак «пусто» — это тип звонка.
- Далее по условию должны встретиться либо 1 цифра, либо 2 цифры, либо знак «пусто» — это код звонка.
- Далее по условию следует от 1 до 6 цифр, точка, 1 или 2 цифры. Причем последние две цифры необязательные. Это длительность звонка (количество).
- Далее по условию должны встиретиться любое количество русских букв, цифр или пробелов до выполенения следующего условия выражения. Это строковое представление единицы измерения длительности звонка.
- Далее по условию следуют от 1 до 9 цифр и в обязательном порядке точка и 2 цифры. Это стоимость звонка.
- Ну и напоследок закрывающий тег td.
