Саммерфилд - Программирование на Python 3 (1077331), страница 81
Текст из файла (страница 81)
Далее те значения, которые не должны быть строками, замещаются значениями соответствующих типов, для чего выполняются те же преобразования строк, что применялись при разборе текста вручную. Мы добавили проверку, чтобы убедиться, что словарь баса содержит ровно девять элементов данных, потому что в случае повреждения записи с информацией об инциденте итератор Кеу ча1ое. (СпбССег() может отыскать слишком много или слишком мало строк ключ=значение.
Оканчивается метод точно так же, как и раньше, — создается новый объект!по!беп1, который затем помещается в словарь инцидентов, после чего вызывающей программе возвращается значение Тгое. Если что-то пойдет не так, блок ехсерс выведет соответствующее сообщение об ошибке и вернет Ра)ае, а блок 1!па!]у закроет файл. 364 Глава 7. Работа с файлами Одной из особенностей, которые делают программный код, анализирующий текст вручную или с применением регулярных выражений, таким коротким и таким простым, является механизм обработки исключений языка РуФ)топ.
Программный код не проверяет результаты преобразований строк в даты, числа или логические значения, и в нем отсутствуют проверки попадания значений в допустимые границы (это делает класс 1пс1оепт). Если какая-либо из этих операций завершится неудачей, интерпретатор возбудит исключение, и мы предусматриваем обработку всех исключений в одном месте, в конце методов. Другое преимущество использования механизма исключений перед явной проверкой на наличие ошибок состоит в хорошей масштабируемости программного кода — даже в случае изменения формата записи и увеличения количества элементов данных программный код, выполняющий обработку ошибок, не будет увеличиваться в объеме.
Запись и синтаксический анализ файлов ХМ~ Некоторые программы используют файлы формата ХМЬ для хранения всех обрабатываемых данных, другие обеспечивают только возможность импорта/экспорта в формате ХМТ. Способность импортировать и экспортировать данные в формате ХМЕ не будет лишней, и поддержку этого формата всегда стоит предусматривать, даже если основным форматом, с которым работает программа, является текстовый или двоичный формат.
Язык РуСЬоп предоставляет три способа записи файлов в формате ХМТл вручную, посредством создания дерева элементов и использования его метода иг1те(), а также посредством создания РОМ и использования его метода иг(те(). Для чтения и анализа файлов ХМЕ используется четыре способа: чтение и разбор файла ХМ1 вручную (не рекомендуется и не рассматривается в этой книге, поскольку может оказаться чрезвычайно сложно корректно обработать некоторые из наиболее туманных и расширенных возможностей) или с использованием парсеров Е1евепсТгее, РОМ или БАХ. Формат ХМЕ записи с информацией об авиационном инциденте приводится на рис. 7.3.
В этом разделе будет показано, как выполнять запись в этом формате вручную и как выполнять запись с помощью дерева элементов и РОМ, а также как читать и анализировать этот формат с помощью парсеров Е1еаептТгее, РОМ и ВАХ. Если вас не интересует вопрос выбора способа чтения или записи файлов в формате ХМЕ, вы можете просто прочитать подраздел «Деревья элементов», следующий ниже, и затем перейти к заключительному разделу главы «Произвольный доступ к двоичным данным в файлах» (стр. 376). 365 Запись и синтаксический анализ файлов ХМ С <?хп! чегвсоп=" 1.0" епсобспс="СТР-8"?> <спссбепсз> <!пс!бепС герогС сб="200702220080990" басе="2007-02-22" а! гога?С !б="80342" а> гсгаГС Суре="СЕ- 172-М" Р!1ОС РЕГСЕпС Ьоогв оо Суре="9.09090909091" р11оС Соса1 Почгв="440" а!бас<="0"> <а!грогс>80иенмам</а!грот> <паггаС!че> ОМ А 80-АНОЬМО ЕНОМ А М10НТ СН088И1МО САМ01МО АТТЕМРТ ТНЕ АТНСНАРТ М1Т А НОМИАУ ЕООЕ ПОНТ ОАМАО!МО ОМЕ РНОРЕССЕЯ.
</паггаС>че> </спссбепс> <спс>бепг> </спс!бесс> </!пс!бел!в> Рис. У.З. Пример записи с информацией об авиационном инциденте в формате ХМ/. Деревья элементов Запись данных с использованием дерева элементов выполняется в два этапа: сначала должно быть создано дерево элементов, представляющее данные, и затем дерево должно быть записано в файл. Некоторые программы могут использовать дерево элементов в качестве основной структуры представления своих данных — в этом случае дерево элементов уже имеется изначально и остается лишь записать его в файл.
Мы рассмотрим метод ехрогС ха1 еС гее( ), разделив его на две части: бег ехрогс ха1 есгее(ве17, г!1епаае): гоос = ха1.еСгее. Е1еаепСТгее. Е1еаепС("1пс!бел!в") Гог 1пс1бепС !и зе17.ча1оез(): е1еаепС = хп1.есгее.Е1еаепСТгее.Е1еаепС("!пс1бепС", герогС !б=зпс1бепс.гЕрсгС 1б, басе=1пс1бепс.баСе. 1воГогваС(), а!гога(С !б=!пс!бесс.а!гсгаГС !б, а1гсгагс суре=!пс!бесс.азгсгагс суре, РС1оС регсЕпС Поогв ОП СуРЕ=всг( !ПС!бЕПС.Р!1ОС РЕГСЕпС Поогв оп Суре), р11ос соса1 посгв=зсг(1пс!бепс.р!1ос соса1 ьоогв), М1ба!г=всг(!пС(1пс!бепс.а!Оа!г))) а!грогС = ха!.есгее.Е1езепСТгее.8оЬЕ1еаепс(е1еаепС, "а1грогС") а1грогС.СехС = !по!бесс.а!гросс,всг!р() паггас!че = ха1.есгее.Е1езепс?гее,8ЬЬЕ1еаепС(е1еаепС, 366 Глава 7. Работа с файлами "паггаттче") паггат(че.техт = 1пс10епт,пагга(1че.зтыр() гост.аррепс(е1евепт) тгее = хв1.аггее.е1евепттгее.е1евепттгее(гост) Метод начинается с создания корневого элемента (<(пс10ептз>).
Затем в цикле выполняются итерации по всем записям с информацией об инцидентах. Для каждой записи создается свой элемент (<1пс10епт>), в котором будут храниться данные об инциденте, а именованные аргументы определяют атрибуты элемента. Все атрибуты должны иметь текстовый формат, поэтому даты, числа и логические значения преобразуются соответствующим образом. Нам не нужно беспокоиться об экранировании символов «Вт», «(» и «)» (или о кавычках в значениях атрибутов), так как модуль парсера дерева элементов (а также модули парсеров 1)ОМ и ЗАХ) делает это автоматически.
Каждый элемент <1пстдепт> имеет два подэлемента, один хранит название аэропорта, а второй — текст комментария. При создании подэлемента мы должны указать родительский элемент и имя тега. Для хранения текста используется атрибут гехт элемента, доступный для чтения и записи. После создания элемента <1пс(0епт> со всеми его атрибутами и подэлементами <а!грогт> и <пагга11че> мы добавляем его в корневой элемент (<тпстэептз>).
В результате у нас получается иерархия элементов, содержащих все записи с информацией об инцидентах, которая затем тривиально просто преобразуется в дерево элементов. тгу: тгее.вг(те((11епаве, "0ТЕ-8") ехсерт Епчтгопвеп(Еггог аз егг. рыпт("(О). тврогт еггог: ( 1)Г.Гогват( оа.рата.ьаэепаве(зуз.агру(0)), егг)) ге(игл Еа(эе гетогп Тгое Запись целого дерева элементов с данными в формате ХМЬ выполняется простым вызовом его метода, выполняющим запись в указанный файл с использованием указанной кодировки символов. До сих пор практически всякий раз, когда мы указывали кодировку, мы использовали строку "от(8".
Она является вполне допустимой для встроенной функции орел(), которая может принимать широкий диапазон кодировок с различными версиями их названий, такими как «Т)Те -З», «()Тг8», «иЫ-8» и «иЫЗ». Но в файлах ХМ1 могут использоваться только официальные названия кодировок, по этой причине название "от(8" нельзя использовать, и мы используем название "Т)Тг-8".' Дополнительную информацию о названинх кодировок вы найдете на сайтах шшш.шВ.огв/Т)Т/2006/ВЕС-хт()Р20060616/№/ч'Т-Епсог)!пВЭес( н шшш. (апа.огВ/аее(япт ел те/с/«агаетег.ее те.
Эапись и синтаксический анализ файлов ХМ! 367 Чтение файла ХМТ с использованием дерева элементов выполняется ничуть не сложнее, чем запись. Запись также выполняется в два этапа: на первом этапе выполняется чтение и анализ содержимого файла ХМЬ, а затем производится обход дерева элементов и заполнение словаря с информацией об инцидентах. Как и прежде, второй этап не является обязательным, если для хранения данных в памяти используется само дерево элементов. Ниже приводится программный код метода !прог! хз1 етгее(), разбитый на две части: бег !прог! ха1 етгее(ве1(, т11епапе).
сгу: Сгее = хз!,етгее,Е1еаепСТгее,рагве(т!1епапе) Еховрт (Епч!гопаепсЕггог, хп1,рагвегв.ехраС.ЕхраСЕггог) аз егг: рг!пс("(О). 1зрогс еггог; (1)т.тогзас( ов.расо.ьавепазе(вув.агру[0]), егг)) гетпгп Ра!ве По умолчанию парсер дерева элементов использует парсер ехраС, именно поэтому мы должны быть готовы перехватывать исключения парсера ехрас. ве1ас)еаг() гог е1епепс 1п сгее,тспба1И "!по!беат"): сгу; баСа = () тот ассг1ьосе !п ("герогс сб", "басе", "а1гсгатс сб", "а!гсгатс суре", "рс1от регсепС Ьоогв оп Суре". "рс1от Сота1 Поогв", "а1ба1г"): баса[ассг1ьисе] = е1езепс.рес(ассг1ьпсе) баса["басе"] = басессае.басес1зенн грсспе( баСа["баСе"], "%у-Срз-%0").бате() баса["р1!ос регсепс поогв оп суре"] = ( (1оас(баса["р11ос регсепс попгв оп суре"])) бата["р11ос соса1 Ьопгз"] = спС( баса["р!1ас соса1 ооогз"]) бата["з1басг"] = Ьоо1(!пС(бата["всба1г"])) баса["а1грогс"] = е1еаепс.т!пб("а!грот!").сехс.зсг1р() паггас1че = е1епепс,тспб("паггас!че"),сехс баса["паггас!че"] = (паггассче.всыр() !т паггат1че !в пот попе е1ве "") 1пссбепт = 1пс!беат(**бата) ве1([1пс!бепт,герогт 1б] = спс1бепт ехсерт (На1чеЕггог, СоокпрЕггог, 1пс!бепСЕггог) ав егг: рг!пс("(О); 1арогс еггог: (!)т,тогпас( ов,раСП.Ьавепаае(зув.агрч[0]), егг)) гетчгп Ра1зе ге!ого Тгое 368 Глава 7.