Главная страница
Навигация по странице:

  • Словари и кортежи

  • Множественное присваивание при работе со словарями

  • Северенс Ч. - Введение в программирование на Python - 2016. Введение в программирование на Python Ч. Северенс М. Национальный Открытый Университет "интуит", 2016


    Скачать 0.65 Mb.
    НазваниеВведение в программирование на Python Ч. Северенс М. Национальный Открытый Университет "интуит", 2016
    Дата20.03.2022
    Размер0.65 Mb.
    Формат файлаdocx
    Имя файлаСеверенс Ч. - Введение в программирование на Python - 2016.docx
    ТипДокументы
    #406251
    страница7 из 12
    1   2   3   4   5   6   7   8   9   ...   12
    Поиск популярных слов


    Видео

    Кортежи (tuples)

    Видео


      1. Кортежи неизменяемы


    Кортеж !) - это последовательность значений, аналогичная списку. Значения, хранимые в кортеже, могуг быть различных типов; они индексируются целыми числами. Важное отличие от списков - кортежи неизменяемы.
    Также кортежи сравниваются и хешируются, что позволяет сортировать их списки и использовать кортежи в качестве ключевых значений в слова рях Питона. Синтаксически, кортеж - это список значений, разделенных запятыми:
    >>> t = 'а', 'Ь', 'с', 'd', 'е'
    Кортежи обычно заключают в круглые скобки, хотя это и не обязательно. Скобки помогают опознать кортеж в исходном коде Пи то на:
    >>> t = ('а' 'Ь' 'с' 'd' 'е')

    ' ' ' '

    При создании кортежа с одним элементом необходимо в конце поставить запятую:

    >>> t1 = ('а',)

    >>> type(tl)



    Без запятой в конце Питон распознает ('а') как выражение в скобках, которое является строкой:
    >>> t2 = ('а')

    >>> type(t2)



    Другой способ образования кортежа - с помощью встроенной фующии tuple. При вызове без аргумента она создает пустой кортеж :
    >>> t = tuple()

    >>> priпt t

    о
    Если аргумент является последовательностью (строкой, списком или кортежем), то результатом вызова функции tнple станет кортеж с последова тельностью элементов:
    >>> t = tuple('lнpiпs')

    >>> priпt t

    ('l'' 'н'' 'р'' ,'i' ,'n' 's')

    Так как tнple является именем конструктора, следует избегать использования этого слова в качестве переменной.
    Большинство операторов списка также работают и с кортежами. Оператор квадратные скобки индексирует элемент:

    >>> t = (,'а' ',Ь' 'с''

    >>> priпt t[O]

    'а'

    'd'' 'е')

    Оператор двоеточие задает диапазон элементов:
    >>> priпt t[l:3] ('Ь', 'с')

    При поп ытке изменить один из элементов кортежа выдается сообщение об ошибке:
    >>> t[O] = 'А'
    ТуреЕпоr: object doesn't support item assigшneпt

    (Оumбка Типа: объект не допускаетизменения его элементов)

    Нельзя изменять элементы кортежа, можно лишь заменить один кортеж на другой:
    >>> t = ('А',) + t[l:]

    >>> prh1t t

    ('А, ' 'Ь'' 'с'' 'd'' 'е')



      1. Сравнение кортежей


    Операторы сравнения работают как с кортежами, так и с другими последовате льностями: Питон сначала сравнивает первые элементы последовательностей; если они равны, сравниваются следующие элементы и так до тех пор, пока не найдутся неравны е элементы. Последующие элементы не рассматриваются (даже если они очень больumе).
    >>> (О, 1, 2) < (О, 3, 4)

    True

    >>> (О, 1, 2000000) < (О, 3, 4)

    True

    Функция сортировки работает аналогичным образом. Сначала она сортирует по первым элементам, в случае равенства первых элементов

    • по вторым и т.д.


    Эта характерная особенность сортировки легла в основу метода под названием DSU (Decorate-So rt-Undecorate): разметка (Decorate) последовате льности с помощью создания списка кортежей, каждый из которых включает элемент исходной последовател ьности плюс один или несколько вспомогат ел ьных ключей сортировки, предшествующих этому элементу; затем сортировка (Sort) списка кортежей с помощью встро енной функции Питона и далее Удаление разметки (Undecorate) путем извлечения отсортированных элементов исходной последова тельности.

    Например, предположим, что есть список слов, которые необходимо отсортировать по их длине - от самого длинного к самому короткому:
    def sort_by_length(words):

    t = list()

    for word in words:

    t.append((leп(word), word)) t.sort(reverse=True)

    res = list()

    for length, word in t:

    res.appeпd(word) return res

    Первый цикл создаст список кортежей , где каждый кортеж - это слово с определенной длиной.
    При сортировке сравниваются первые элементы - длины слов, вторые элементы рассматриваются лишь при равенстве первых. Ключевой аргумент reverse=True предписывает выполнять сортировку в порядке убывания.
    Второй цикл проходит список кортежей и формирует список слов в порядке убывания по длине.


      1. Присваивание кортежей


    Одной из особенностей синтаксиса языка Питон является возможность размещать кортеж слева от оператора присваивания. Это позволяет за один раз присваивать значение более чем одной переменной.
    В примере мы используем двухэлементный список представляет собой последовательность) и присваиваем второй его элементы переменным х и у в одном присваивания.
    >>> m = [ 'have', 'ft.m' ]

    >>> х, у = ш

    >>> х

    (который первый и операторе

    'have'

    >>> у

    'fun'

    >>>

    Здесь нет ничего загадочного, Питон просто преобразует синтаксис присвоения кортежа в следующий код :

    >>> m = [ 'have', 'fi.m' ]

    >>> х = m[O]

    >>> у = m[ l ]

    >>> х

    'have'

    >>> у

    'fun'

    >>>

    Стилистически, когда кортеж ставится с левой стороны оператора присваивания, скобки обычно опускаются, но следующий код в той же степени допустим:
    >>> m = [ 'have', 'fi..m' ]

    >>> (х, у)= m

    >>> х

    'have'

    >>> у

    'fun'

    >>>

    Хитроумное использование присваивания кортежей позволяет нам поменять местами значения двух переменных в одном операторе:

    >>> а, Ь = Ь, а
    Обе части этого оператора - кортежи, но слева - кортеж переменных, а справа - кортеж выражений. Каждое значение справа присваивается

    соо т ветств ующей переменной слева. вычисляются до любых присваиваний.

    Все вы ражения справа
    Количество переменных слева должно быть равно количеству значен ий справа:
    >>> а, Ь = 1, 2, 3

    ValueError: too many values to unpack

    (Ошибка Значений : слиllЖDм много значений для распаковки)

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

    >>> addr = 'шo 11ty@ p ytl10n.or g'

    >>> unaшe, doшam = addr.split('@')
    Возвращаемое значение метода split является списком из двух элементов; первый элемент присваивается переменной unaшe, второй переменной domain.
    >>> priпt tmaшe шonty

    >>> priпt domain python.org


      1. Словари и кортежи


    У словарей есть метод с названием ''nerпs", который возвращает список кортеж ей, где каждый кортеж - это пара ключ-значениеill:

    >>> d = {'а':10, 'Ь':1, 'с':22}

    >>> t = d.iterпs()

    >>> priпt t

    [('а' , 10), ('с', 22), ('Ь', 1)]

    Как и следовало ожидать, в словаре элементы располагаются в произвольном порядке. Но, поскольку список кортежей является списком и кортежи можно сравнивать - можно сортировать список кортежей. Преобразование словаря в список кортежей - это способ вывода содержимого словаря, отсортированного по ключу:
    >>> d = {'а':10, 'Ь':1, 'с':22}

    >>> t = d.items()

    >>> t

    [('а', 10), ('с', 22), ('Ь', 1)]

    >>> t.sort()

    >>> t

    [('а', 10), ('Ь', 1), ('с', 22)]

    Новый список сортируется в алфавитном порядке по значению ключа.


      1. Множественное присваивание при работе со словарями


    Сочетая использование функции items, присваивание кортежей и цикл for, можно написать изящный фрагмент кода для перечисления ключей и их значений в словаре в одном цикле:
    for key, val.in d.items():

    priпt vaL key

    В этом цикле используются две итерационные переменные, потому что функция items возвращает список кортежей; пара переменных key, val также образует кортеж, который пробегает все пары ключ/значение, содержащиеся в словаре .
    После каждой итерации переменные key и val переходят к следующей паре ключ/значени е, содержащейся в словаре (в порядке, задаваемой хеш-функцией).
    На выходе цикла получим:

    Оа 2с lb

    Значения напечатаны в порядке, задаваемом хеш-функцией (т.е. без определенной упорядоченности).
    Сочетая два указанных метода, мы можем вывести содержание словаря, которое отсортировано по значениям, содержащимся в парах ключ/ значение.
    Для этого сначала создается список кортежей , где каждый кортеж представляет собой пару (значение, ключ).Метод iteшs даст нам список кортежей вид а (ключ, значение), однако на этот раз мы хотим выполнить сортировку по значениям, а не по ключам.
    Когда список кортежей (значение, ключ) создан, несложно отсортировать его в обратном порядке и напечатать новый отсортированный список.
    >>> d = {'а':10, 'Ь':1, 'с':22}

    >>> l = list()

    >>> for key, val in d.iteшs() :

    ... La ppend( (vai key) )
    >>> l

    [(10, 'а'), (22, 'с'), (1, 'Ь')]

    >>> Lsort(reverse=True)

    >>> l

    [(22, 'с'), (10, 'а'), (1, 'Ь')]

    >>>

    Создав вручную список кортежей, в которых значение ключа является первым элементом, мы можем отсортировать список и получить содержим ое словаря, отсортированное по значениям ключей.


      1. Наиболее часто встречающиеся слова

    Вернемся назад к нашему примеру - отрывку текста из произведения ''Ромео и Джульетт а", действие 2, сцена 2. Мы можем дополнить нашу программу, если применим технику вывода десяти наиболее распространенных в тексте слов, используя следующий код:
    import sning

    fhaпd = opeп('romeo-full.txt') coш1ts = dict()
    for liпe iп fhaпd:
    liпe = liпe.traпs late(No пe, striпg.pш1etuation) liпe = liпe.lower()

    words = liпe.sp lit()
    for word iп words:

    if word поt iп coШ1ts:
    coШ1ts[word] = 1 else:

    coШ1ts[word] += 1

    # Sort the dictionary Ьу value

    1st = list()

    for key, val iп coШ1ts.items():

    lst.appeпd( (val, key) ) lst.sort(reverse=True) for key, val iп lst(:10) :

    priпt key, val

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

    т.е. ключи. Таким образом, кортежи с одинаковыми значениями будуг сорти ров аться по ключам в алфавитном порядке.
    В конце мы запишем изящный цикл for, который выполняет множественное присваивание в каждой итерации и выводит десять наиболее распространенных слов с помощью перебора части списка (Jst[:10]).
    Вывод наконец- то выглядит так, как это требуется для анализа частоты слов.
    61 i

    42 and

    40 romeo

    34 to

    34 the

    32 thoн

    32 juliet

    30 that

    29 шу

    24 thee

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


      1. Использование кортежей в качестве ключей в словарях


    Кортежи, в отличие от списков, хешируемы, поэтому, если мы .хотим создать составной ключ для использования в словаре, нужно использовать кортеж в качестве ключа.
    Например, нам понадобится составной ключ, если мы за.хотим создат ь телефонный справочник, который отображает пары (фамилия, имя) на телефонные номера. Предположим, что переменные last (фамилия - last name), first (имя - firstname) и nшnber(номер) определены, тогда мы

    можем внести запись в справочник следующим образом: directory[last,first] = пшnЬеr

    Вы ражени е в скобках является кортежем. Мы можем использовать присваиван ие кортежей в цикле for для печати содержимого справочник а.
    for last, first in directory:

    priпt first, last, directory[last,first]

    Цикл перебирает ключи справочника, которые являются кортежами . Происходит присваивание элементов каждого кортежа переме нным last и first, затем выводится имя и соответствующий телефонный номер.


      1. Последовательности: строки, списки, кортежи...


    Мы у,целяли внимание в основном спискам кортежей, но почти во всех примерах в этой главе используются и списки списков, кортежи кортежей, списки кортежей . Чтобы не переч ислять все возможные комбинации , проще говорить о последовательностях последовательностей.
    Во многих случаях различные виды последовательностей (строки, списки, кортежи) могут использоваться как взаимозаменяемые. Но как выбрать конкретный тип среди всех возможных? Начнем с очевидного: строки ограничены тем, что их элементами являются символы. К тому же строки неизменяемы. Если необходима возможность изменения символов в строке (а не просто создание новой строки), можно использовать вместо строк списки символов.
    Списки более распространены, чем кортежи, в основном потому, что их можно изменять. Но ниже приведено несколько случаев, когда п редпочтение отдается кортежам


        1. В некоторых случаях, нап ример, в операторе return, синтаксически проще создать кортеж, чем список. В других случаях можно предпочесть список.




        1. Если мы хотим использовать последовательность как ключ в словаре , нам обязательно нужен неизменяемый тип, например, кортеж или строка.

        2. Если последовательность используется в качестве аргумента функции, применение кортежей уменьшает вероятность незапланированного поведения благодаря ссылкам.


    Так как кортежи неизменяемы, они не позволяют применять такие методы, как sort и reverse, которые изменяют содержимое списка. Однако Питон предоставляет встроенные функции sorted и reversed (сортировка и обращение), которые принимают любую последовательность в качестве параметра и возвращают новый список с теми же элементами в другом порядке .


      1. Отладка


    Списки, словари и кортежи являются примерами структур данных; в этой главе мы начали рассматривать сложные ("составные'') структуры данных, например, списки кортежей, словари, которые содержат кортежи в качестве ключей и списки в качестве значений. Сложные структуры данных очень полезны, но они часто приводят к ошибкам, которые я называю ошибки формы; эти ошибки возникают, когда структура данных имеет неправильный тип, размер или состав, или, возможно, когда при написании некоторого кода вы забыли форму этих данных.
    Например, если вы ожидаете список с одним целым числом, а вам предоставляется обычное целое число (не в списке), программа работать не будет.
    При отладке программы и особенно при исправлении тяжелой ошибки пытайтесь выполнить четыре вещи.
    Чтение: проверьте свой код, прочитайте его еще раз, чтобы убедиться, дейс твительно ли он выражает то, что вы хотели.

    Выполнение: экспериментируйте путем внесения изменений и запускайте различные версии. Часто, если вы вставили правильный код в правильное место в программе, проблема становится очевидной, но

    иногда необходимо потратить значительное время на вспомогательную работу.
    Размьшm яйте: найдите время на размьшmения! Что это за ol.I..lliбкa : синтаксическая, времени выполнения, семантическая? Какую информацию можно получить из сообщений об ol.I..lliбкax или из вывода программы? Какая 01.I..lliбкa может породить эту проблему? Какие последние изменения были внесены до появления 01.I..lliбки?
    Отступление: бывает так, что лучшее из того, что можно предпринять - это отменять последние изменения, пока вы не вернетесь к программе, которая работ ает. Затем можно начать пошаговое восстановления.
    Начинающие программисты часто застревают на одном из этих действий и забывают о других.
    Каждое действие имеет свои собственные ol.I..lliбки. Нап ример, чтение кода позволит обнаружить опечатку, но не поможет, если ol.I..lliбкa заключается в концептуальном непонимании. Если вы не понимаете, что делает ваша программа, вы не сможете обнаружить ol.I..lliбкy, даже если прочтете код 100 раз, потому что ol.I..lliбкa у вас в голове . Экспериментирование может помочь, особенно при запуске нeбoльl.I..llix простых тестов. Но если вы начнете экспериментировать без обдумывания и чтения кода, то в конце концов можете дойти до "программирования методом случайного блуждания", которое представляет собой процесс внесения случайных изменений до тех пор, пока программа не станет работать правильно. Излишне говорить , что случайное блуждание может длиться неопределенно долго. Не лучше ли немного подумать?
    Отладка похожа на экспериментальную науку. Необходимо иметь хотя бы одну гипотезу о причинах проблемы. При наличии двух и более возможностей постарайтесь придумать тест, исключающий одну из них.
    Небольшой перерыв помогает дальнеЙJ.lll.-lМ размышлениям. Также полезны обсуждения. Если вы объясните проблему кому-то (или даже себе), возможно, вы найдете ответ еще до того, как закончите задавать вопрос.
    Однако даже лyчl.I..llie способы отладки бессильны, когда в коде слишком




    много ошибок или когда код, который вы хотите исправить, слишком большой и сложный. Иногда лучше отступить и упростить программу, пока не получится то, что работает и всё еще находится под вашим контролем.
    Начинающие программисты зачастую неохотно вносят изменения, боясь удалить строку кода, даже когда она неп равильн ая. Для спокойствия скопируйте программу в другой файл перед началом его правки. При необходимости легко можно будет вставить фрагменты исходного кода назад.
    Поиск серьезных ошибок требует чтени я, запусков, размышлений, а иногда и отмены последних изменений. Если вы застряли на одном из действий, попробуйте другие.


      1. Глоссарий


    Сравнимый (comparaЫe): тип , два значения которого можно сравнивать друг с другом, определяя, что первое значение больше, меньше или равно второму. Сравнимые типы можно помещать в список и сортировать.
    Структура данных (data structнre): совокупность связанных значений, часто представленная в виде списков, словарей, кортежей и т.д.
    DSU: Сокращение от "decorate-sort-undecorate ," (декорирование­ сортировка-раздекорирование) - метод, который включает в себя построение списка кортежей, сортировку и извлечение части результата .
    Сборка (gatЬer): операция формирования кортежа путем объединения произвольного числа аргументов.
    Хешируемый (hashaЫe): тип , имеющий хеш-функцию. Неизменяемые типы, такие как целые или вещественные числа и строки, являются хешируемыми; изменяемые, такие как списки и словари, - нет.
    Разброс (scatter): операция использования последовательности в качестве списка аргументов .
    Форма структуры данных (sI-1ape): совокупность типа, размера и состава

    структуры данных.
    Одноэлементный (singleton): список (или другая последовательность) с одним элементом.
    Кортеж (tuple): неизменяемая последовательность элементов.
    Присваивание кортежей (tuple assignment): последовательности, стоящей с правой стороны присваиван ия, кортежу переменных с левой стороны.

    присваивание от оператора Правая сторона

    сначала вычисляется, затем вычисленные значения присваиваются переменным с левой стороны.
    2О.11. Упражнения
    Упражнение 20.1.
    Доработайте пе рвоначаль ную программу следующим образом: она должна читать и разбирать поле ''From" каждого сообщения и извлекать адрес из него. С помощью словаря нужно для каждого человека подсчитать число отправленных им сообщений.
    После завершения обработки данных выводится имя человека, отправившего наибольшее число сообщений, при помощи создания списка кортежей (количество, e-mail) из словаря и последующей сортировки списка в обратном порядке.
    Пример:
    From stephen.marquard@uct .ac.za Sa t Jan 5 09:14:16 2008 Enter а file ваше: mbox-short.txt

    cweв@ iupuiedн 5

    Enter а file ваше: mbox.txt zq.ian@шnich.edu 195

    Упражнение 20.2.
    Программа должна рассчитать распределение количества сообщений для каждого часа в сутках. Номер часа можно извлечь из поля ''From"

    сообщения, найдя в нем подстроку, задающую время, и разделив ее на части по двоеточиям. После подсчета количества сообщений для каждого часа выведите значения счетчиков, по одному на каждую строку, отсортировав их по номеру часа, как показано ниже.
    Пример выполнени я программы:
    python timeofday.ру

    Enter а file паmе: mbox-short.txt
    04 3

    06 1

    07 1

    09 2

    10 3

    11 6

    14 1

    15 2

    16 4

    17 2

    18 1

    19 1

    Упражнение 20.3.
    Напиumте функцию most_frequent (наиболее частые), которая получает строку и выводит ее буквы в порядке убывания частоты. Найдите образцы текста на разных языках и посмотрите, как частоты букв меняются в разных языках. Сравните свои результаты с таблицей по адресу ссылка: wikipedш.org/wiki/Letter_frequeпcies.
    l) Интересный факт: слово tuple - ''кортеж" - произоuто от названий последовательностей чисел различной длины: двухэлементных, трехэлементны х, четырехэлементных, пяти-, шести- и т.д. (douЫe, triple, quadruple, quituple, sextuple, ... ).

    2) Пи т он не воспринимает синтаксис буквально . Нап ример , если попытаться выполнить команду для словаря, она не будет работать.

    3) Версия Питона 3.0 в данном случае работает немного иначе.

    10 часто встречающихся слов
    Видео
    Регулярные выражения


    Видео
    Ранее нам часто приходилось, читая файлы, искать текстовые шаблоны и извлекать нужные нам фрагменты строк. Для этого мы применяли строковы е методы, такие как s р 1 i t (расщепление) и f i nd (поиск), и использовали списки и подстроки для выделения частей строк.

    Задача поис ка и выделения встречается очень часто, поэтому Питон содержит достаточно мощную библиотеку, работающую с регулярными выражениями, которая предоставляет элегантные решения большинства подобных задач. Причи на, почему мы не рассматривали регулярные выражения раньше в этой книге, состоит в том, что это очень мощный инструмент, овладение которым не дается сразу, а к синтаксису регулярных выражений нужно привыкнуть.
    Регуляр ные выражения представляют собой почти что небольшой самостоятельный язык программирования для поиска и разбора строк. Ему зачастую посв ящают целы е книги. В этой главе мы затронем лишь базовые возможности регулярных вы ражений. Более детальное описание доступно по адресам: ссылка: http://en.wж jpedia.or g/wikVR.eg uJar_expression и ссылка: http://docs. python.org/liЬrary /re .l1trnl.
    Библиотека для работы с регулярными выражениями должна быть импортирована в вашу программу. Простейший пример использования регулярных выражений - функция поиска search ( ) . Следующая программа демонстрирует тривиальное использование функции поис ка.
    import re

    hand = open('mbox-short.txt') for line ш haпd:

    liпe = line.rstrjp()

    if re.search('From:', liпe) :

    priпt liпe

    Здесь открывается файл и в цикле просматриваются все его строки;

    функция поиска регулярного выражения s e a r c h () используется только для того, чтобы напечатать строки, содержащие фрагмент "From:". Данная программа не использует всей силы регулярных выражений, поскольку мы могли бы попросту воспользоваться строковым методом line. find () и получить тот же самый результат. Сила регулярных выражений раскрывается, когда мы добавляем специальные символы в шаблон поиска, что позволяет более точно задавать соответствие строк шаблону. Применение этих специальных символов в регулярном выражении дает возможность устанавливать сложное сопоставление и извлечение фрагментов текста с помощью совсем короткого программного кода.

    Например, символ "/\" (крышка) в регулярном выражении означает фрагмент в начале строки. Можно изменить нашу программу так, чтобы она находила только строки , содержащие слово ''From: " в начале строки:
    import re

    hand = open('mbox-short.txt') for line in haпd:

    liпe = line.rstr ip()

    if re.search('AFr o ш:', line) :

    priпt line

    Теперь шаблону сопоставляются только строки, начинающиеся с фрагмента ''From: ". Это всё ещё совсем простой пример, который мы могли бы реализовать и с использованием метода s t ar t s wi th () из библиотеки работы со строками. Но он показывает, как специальные символы в регулярных выражениях расширяют наши возможности при сопоставлении фрагментов текста шаблону поиска.


      1. Сопоставление символов в регулярных выражениях


    Имеется ряд других специальных символов, дающих возможность строить еще более эффективные регулярные выражения. Наиболее часто используемый специальный символ - это точка, которая сопоставляется любому символу.

    В следующем примере регулярное выражение "F..m:" сопоставляется любой из строк "From:", ''Fxxm:", ''F12m:", or ''F!@m:", поскольку точка в регулярном выражении соответствует любому символу.

    import re

    hand = open('mbox-short.txt') for line in haпd:

    liпe = line.rstrip()

    if re.search(' ЛF..m:', line) :

    priпt line

    Это особенно эффективно в сочетании с возможностью указать, что символ может быть повторен произвольное количество раз, - для этого в регулярном выражении применяются специальные символы "*" или "+". Они означают, что вместо одного символа строки поиска сопоставляется ноль или более символов в случае звёздочки и один или более символов в случае знака плюс.
    Мы можем еще более сузить множество строк, которые сопоставляются регулярному выражению, используя повторение произвольного символа (т.е. точки) в следующем прим ере:

    import re

    haпd = open('mbox-short.txt') for line in hand:

    liпe = line.rstrip()

    if re.search ('AF ro m:.+@', line):

    priпt line

    Шаблон поиска "ЛF rom:+. @" успепmо сопоставляется всем строкам, начинающимся со слова ''From:", за которым следует один или более произвольных символов и затем символ @. Например, он соответствует следующей строке:
    From:stephen.marquard @нct.ac.za
    Часть шаблона ".+" можно представлять себе как фрагмент, который расширяется до соответствия всем символам между двоеточием и

    символом @.
    From:.+@
    Удобно представлять плюс и звездочку как расширяющие симво лы. Например, в следующей строке символу @ шаблона будет соо т ветствовать пос ледний символ @ строки, тогда как фрагмент ".+" шаблона расширяется до всех символов после двоеточия, предшествующих ему:
    From: stephen.marquard @нct.ac.za, csev@шnich.edu, and cwen@iupuiedн
    Можно заставить звездочку или плюс не быть столь "ненасытными", добавив другой специальный символ - см. подробную документацию по выключению их "жадного" поведения.


      1. Извлечение данных с помощью регулярных выражений


    Для выделения данных из строки

    f inda11 ( ) , извл екаю щий все

    Питон предоставляет метод подстроки, соответствующие

    регулярному выражению. Пусть мы хотим извлечь всё, что похоже на адрес электронной почты, из любой строки, независимо от ее формата. Например, мы хотим извлечь e-mailадрес из любой из следующих строк:
    Froш stephen.marquard@нct.ac.za Sa t Jan 5 09:14:16 2008 Retшn-Path:


    for ; Received:(from apache@locallюst) Autlюr: stepheп.ma rquard@uct.ac. za

    Не хотелось бы писать отдельный код для каждого типа строк, разбирая по-своему каждую строку. П риведенная ниже программа использует метод f i n da 1 1 ( ) для нахождения всех строк с e-mail адресом и извлечения одного или нескольких адресов из таких строк.
    import re

    s = 'Hello froш csev@ шnich.edн to cwen@iupuiedu about tl1e шee tiпg @2РМ'

    1st = r e. findall('\S+@\S+', s) priпt 1st

    Метод f i nd a 1 1 () прои зводит поиск регулярного выражения в строке, переданной ему в качестве второго аргумента, и возв ращает список всех ее подстрок, которые выглядят как e-mail адреса. Мы используем

    специ альную двухсимвольную последов ательн ость \S длины 2, которая сопоставляется любому непробельному (пon-whiet space) символу. На в ыходе программы получим :
    ['csev@шnich.edu', 'cweп@iupui.edu']
    Сопост авляя регулярное вы ражение, мы находим все подстроки, имеющие хотя бы один непробельный символ, за которым следует символ @, после которого в свою очередь идет один или более непробельный символ. Шаблон '\S+" аналогично сопоставляется максимально длинно й последовательности неп робельных символов (это называют "жадным" поведением в регулярных вы ражениях).
    Регулярное выражение сопоставляется дважды (csev@шnich.edu и cwen@iupui.edu), но оно не соответствует подстроке "@2РМ", поскольку перед симво лом @ нет непробельных симв олов. Мы можем использовать это регулярное выражение в программе, читающей все строки в файле и печат ающей всё, что выглядит как e-mailадрес:
    import re

    hand = open('mbox-short.txt') for line in haпd:

    liпe = liпe.rstrip()

    х = re. fiпdall('\S +@\S+', liпe)

    if len(x) > О :

    priпt х

    Из каждой прочитанной строки извлекаются все подстроки, соответствующие нашему регулярному вы ражению . Поскольку метод f i n d a l l () возв ращает список , достаточно проверить, что число его элементов больше нуля, чтобы напечатать строки, содержащие e-mail ад реса.

    Применив программу к файлу mb o x . t x t , п ол учим следующий результат:

    ['wa gnermr@ iupui.edu'] ['cwen@iupui.edu'] ['']

    ['<2008010321 22.m03LMFo4005148@пakamшa.uits.iupui.edu>'] [';']

    [';'] [';'] ['apache@locallюst)'] ['soшce@collab.sak aiproject.org;']


    ;
    Некоторые из этих e-mail адресов содержат некорректные символы "<11 или 11 11 в начале либо конце. Укажем, что нас интересует лишь часть строки, начинающаяся и заканчивающаяся буквой или ци фрой. Для этого исполь зуем другую возможн ость, предоставляемую регулярными выражениями. Квадратные скобки в ни х применяются для указания множества допустимых символов, используемых при сопоставлении . В этом смысле шаблон ''\S11 соответствует множеству всех непробельных символов. Теперь мы более явно укажем множество сопоставляемых символов.
    Вот наше новое регулярное выражение:
    [a-zA-Z0-9]\S*@\S*[a-zA-Z]
    Оно несколько сложнее, теперь уже видно, почему регулярные выражени я можно считать самостоятельным языком. Данное регулярное выражение означает, что мы ищем подстроки, начинающиеся с одиночно й строчной буквы, прописной буквы или


    ,
    цифры 11[a-zA-Z0-9]11 за которой следует ноль или более непробельных

    символов ''\S*", даль ше идет символ @, потом ноль или более непробельных символов ''\S*11 и в конце строчная или прописная буква. Отметим , что мы заменили 11+ 11 на "* 11 для указания нуля или более непробельных символов, поскольку фрагмент " [a-zA-Z0-9] 11 уже представляет собой один непробельный символ.
    Помните,что"* 11 или 11+"применяютсякодномусимволу,стоящем у

    непосредственно слева от звездочки или плюса. Если мы используем это выражение в нашей программе, выходные данные будут более чистыми:
    import re

    hand = open('mbox-short.txt') for line in haпd:

    liпe = line.rstrip()

    х = re.fiпdall('[a- zA-Z0-9]\S+@\S+[a- zA-Z]', liпe)

    if lеп(х) > О :

    print х ['wagnermr@iupui.edu'] ['cwen@iupui.edu']

    ['postmaster@collab.sakaiproject.org']

    ['200801032122.m03 LMFo4005148@nakamшa. uits.iupui.edu'] ['soшce@collab.sakaiproject.org'] ['soшce@collab.sakaiproject.org'] ['soшce@collab.sakaiproject.org']

    ['apache@localhost']

    Отметим, что из строк, содержащих фрагмент "soшce@collab.sakai project.org", наше регулярное выраж ение исключило два символа в конце строки (">;"). Это произошло потому, что , добавив фрагмент "[a-zA-Z]" в конец нашего регулярного выражения, мы указали, что подстрока, которая сопоставляется регулярному выражению, обязательно должна заканчиваться буквой. Поэтому сопоставление заканчивается, как только мы доходим до символа ">" в конце "sakaiproject.org>;" - на последней "сопоставимой" букве (в данном случае "g''). Также отметим, что каждая строчка вывода программы представляет собой одноэлементный список Питона, единственным элементом которого является строка.

      1. Сочетание поиска и извлечения


    Пусть мы хотим найти числа во всех строках, которые начинаются с фрагмента "Х-", на прим ер:
    X-DSPAМ-Co пfideпce: 0.8475

    X-DS PAМ-Probab ility: 0.0000

    Мы не хотим выделять числа в плавающем формате из любых строк - только из строк, имеющих вышеуказанный синтаксис. Для этого можно использовать следующее регулярное выражение:
    ЛХ- .* : [О-9.] +

    Здесь указывается, что мы выбираем только стро ки, начинающиеся с фрагмента "Х-", за которым следуют ноль или более произвольных символов ".*", затем двоеточие ":" и пробел. После пробела ищем один или более символов, каждый из которых является либо цифрой 0-9, либо точкой "[О-9 .] + ". Отметим, что точка внугри квадратных скобок обозначает обычный символ точки, а не произвольный символ (т.е. подстановка произвольного символа не действует внугри квадратных скобок).
    Это очень компактное выражение , и оно выделяет из многообразия строк только те, которые нас интересуют:
    import re

    hand = open('mbox-short.txt') for line ш haпd:

    liпe = line.rstrip()

    if re.search(' ЛX \S*: [О- 9 .]+ ', line):

    priпt line

    Выполнив программу, мы успешно отфильтруем только нужные нам строки.
    X-DSPAМ-Confideпce: 0.8475

    X-DSPAМ-Probability: 0.0000 X-DSPAМ-Confideпce: 0.6178 X-DSPAМ-Probability: 0.0000

    Но теперь необходимо решить проблему извлечения чисел с помощью

    метода s р1 i t . В принципе, и это совсем не сложно, но можно использовать другую возможность, предоставляемую регулярными выраж ени ями - одновременный поиск и разбор.
    Круглые скобки - это также специальные символы в регулярных выражениях. Когда мы ставим круглые скобки, они игнорируются при сопоставлении строки регулярному выражению, однако при использовании метода f i nda 11 ( ) скобки указывают, что, сопоставляя регулярное выражение целиком подстроке, мы извлекаем лишь ту часть подстроки, которая соответствует части регулярного выражения в скобках. Внесем следующее изменение в нашу программу:
    irnport re

    hand = open('mbox-short.txt') for line in haпd:

    line = line.rstrip()

    х = re.fiпdall(Л' X\S*: ([0-9 .] + )', line)

    if len(x) > О :

    pr iпt х

    Вместо вызова метода search () мызаключаем в круглые скобки ту часть регулярного выражения, которая представляет число в плавающем формате; тем самым мы указываем, что метод f i n d a l l () должен возвращать лишь часть сопоставленной подстроки, представляющую число.
    На выходе этой программы получаем:
    ['0.8475']

    ['О.0000']

    ['О.61 78']

    ['О.0000']

    ['О.6 961']

    ['0 .0000']


    Числа все еще содержатся в списке и должны быть преобразованы из строк в вещественные числа, но фактически мы уже воспользовались

    мощью регулярных выражений , чтобы найти и извлечь информацию, которая нас интересует.
    Еще один пример применения этой техники: рассмотрим файл, который содержит некоторое количество строк в форме:
    Details: http://soшce.sakaiproject.org/viewsvn/?view=rev&rev=39772
    Пусть нам нужно извлечь все номера ревизий (целые числа в концах подобных строк). Можно использовать следующую программу:
    import re

    hand = open('mbox-short.txt') for line in hand:

    line = line.rstrip()

    х = re.:fiпdall('ЛDetails:.*re v=([0-9.] +)', line)

    if len(x) > О:

    priпt х

    Здесь регулярное выражение означает, что мы ищем строки, начинающиеся со слова 'Details:", за которым следует произвольное количество любых символов".*", затем фрагмент ''rev=" и далее одна или несколько цифр. Мы ищем строки, соответствующие всему выражению, но хотим извлечь из них только числа в концах строк, поэтому мы заключаем фрагмент" [О-9 ] +" в круглые скобки.
    В результате работы программы получаем:
    ['39772']

    ['39771']

    ['39770']

    ['39769']


    Помните, что фрагмент "[О-9]+" "жадный ", он пытается выделить максимально большую подстроку из цифр перед ее извлечением. Это "жадное" поведение объясняет, почему выделяются все пять цифр каждого числа. Расumрение происходит в обоих направлениях, пока не

    встретится либо не-цифра, либо начало или конец строки.
    Теперь мы можем использовать регулярные выражения, чтобы переписать упражнение, рассмотренное ранее в этой книге, в котором нас интересовало время суток каждого письма в электронной почте. Мы искали строки вида:
    Froш stephen.marquard@uct.ac.za Sat Jап 5 09:14:16 2008
    Мы хотим извлечь час из каждой такой строки. Раньше мы делали это с помощью двух вызовов метода s р 1 i t . Сначала строка разделялась на слова, затем извлекалось пятое слово, которое в свою очередь разделялось с помощью двоеточия для извлечения интересовавll.П1х нас двух си мволов.
    Хотя это и работало, мы получили в результате довольно ненадежный, хрупкий (brittle) код, предполагающий, что исходные строки правильно отформатированы. Если добавить проверку оll.П1бок (или большой блок try/except), чтобы программа не отказывала при некорректно отформатированных входных данных, код раздулся бы до 10-15 строк и стал бы трудно читаемым.
    Ту же задачу можно реll.П1ть намного проще с помощью следующего регулярного выражения:

    ЛFrom .* [О-9][0-9]:

    Оно озн ачает, что мы ищем строки, начинающиеся с фрагмента 'From " (обратите внимание на пробел!), за которым следует произвольное количество любых символов ".*", затем пробел и дальше две цифры ''(0- 9)[0-9]", после которых стоит символ двоеточия. Это точное определение строк, которые мы ищем.
    Для извлечения часа с помощью метода findall () мы заключаем в круглые скобки часть вы ражения, соответствующую двум цифрам:

    ЛFrom .* ([О-9][0-9]):

    В результате пол учаем программу:

    import re

    hand = open('mbox-short.txt') for line in haпd:

    liпe = line.rstrip()

    х = re.fiпdall('ЛFrom .* ([О-9][0-9]):', line)

    if len(x) > О : print х

    На выходе она выдает

    ['09']

    ['18']

    ['16']

    ['15']



      1. Символ "Escape"


    Поскольку мы используем специ альные символы в регулярных выражениях для указания начала или конца строки и подстановки произвольного символа, нам необходим также способ указать, что эти символы в отдельных случаях испо льзуются как ''нормальные", чтобы просто сопоставить их с обычными символами, такими как доллар "$" или крыlllКа "Л".
    Э то можно сделать, поставив перед защищаемым символом обратную косую черту '\" (backslas\1). Например, можно найти обозначения денежных сумм с помощью следующего регулярного выражения:
    import re

    х = 'We just received $10 .00 for cookies.'

    у = re.fiпdall(\'$[0- 9.]+',x)

    Поскольку мы поставили обратную косую черту перед знаком доллара, он будет сопоставляться с реальным символом доллара во входной строке, вместо того, чтобы обозначать конец входной строки; оставшаяся часть регулярного вы раже ни я сопоставляется с одной или более цифрой или точкой.
    Замечание: символы внутри квадратных скобок не считаются специальными. Когда мы пишем "[О-9 .] ", это действительно означает

    цифру или точку. Вне квадратных скобок точка означает подстановку произвольного символа. Внутри них точка означает точку.

      1. Выводы


    Пока мы лишь затрон и тематику ре ярных выражений, познакомившись с языком задания рег ярных выражений. Они представляют собой шаблоны поиска, включающие специальные символы. С помощью рег ярных выражений мы определяем задание для поисковой системы - что именно мы хотим найти и что извлечь из найденных строк. Ниже приведены некоторые специальные символы и специальные последовательности:
    /\
    Соответствует началу строки.
    $
    Соответствует концу строки.

    Соответствует любомусимволу (символ подстановки, wildcard).
    \s
    Соответствует пробельному символу (whitespace).
    \S
    Соответствует неп робельному символу (противоположен \s).
    *

    Действует на непосредственно предшествующий символ и соответствует цепочке из н я или более предшествующих символов.
    *?

    Действует на непосредственно предшествующий символ и соответствует цепочке из нуля или более предшествующих символов, выделенной в "нежадном" режиме.
    +
    Действует на непосредственно предшествующий символ и соответствует цепочке из одного или более предшествующих символов.
    +?
    Действует на непосредственно предшествующий символ и соответствуетцепочке из одного или более предшествующих символов, выделенной в "нежадном" режиме.
    [aeiou]
    Соответствует одному символу из указанного набора. В данном примере может сопоставляться символам "а", "е", "i", "о", ''u" и никаким другим.
    [a- z0-9 ]
    Можно указывать диапазон символов с помощью знака минус. В данном примере задается один символ, являющийся строчной буквой или цифрой.
    (ЛA- Za-z]
    Если первым символом в обозначении набора является крышка "Л", то смысл обозначения меняется на обратный - любой символ, не входящий в указанный набор . В данном примере задается один символ, не являющийся прописной или строчной буквой.
    ()
    Круглые скобки в регулярном выражении игнорируются при сопоставлении строки и регулярного выр ажения, но позволяют извлечь указанную в скобках часть строки вместо всей строки при использовании метода f i nda l 1 ( ) .


    Соответствует пустой строке в начале или конце слова.

    Соответствует пустой строке всюду, за исключением начала или конца слова.
    \d
    Соответствует десятич ной цифре; эквивалентно выражению [О-9 ].
    \D
    Соответствует любому символу, отличному от десятичной цифры; эквивалентно выражению [ЛО-9 ] .


      1. Бонусный раздел для пользователей UNIX


    Поиск в содержимом файлов с помощью регулярны х выражений был встроен в операционную систему UNIX, начиная с 1960-х годов, и в

    настоящее время доступен практически программированиях в той или иной форме.

    во всех языках
    Как п равило , в системе UNIX имеется программа с консольным интерфейсом под названием grep (Generalized ReguJar Expression Parser), которая работает примерно так же, как описанный в этой главе метод s е аr с h ( ) . Таким образом, если вы работаете в системах Maciпtosh или Linux, вы можете попробовать следующую команду в консольном окне:
    $ grep 'ЛF ro m:' mЬox-s hort.txt Froш: stepheп.marquard@uct.ac.za From: louis@шedia.berkeley.edн From: zqiaп@шnich.edu

    From: rjlowe@iнpui.edн

    Команда указывает утилите grep напечатать все строки в файле

    mb o x - s h or t . t x t , на чинающиеся с фрагмента ''Froш:".
    Если вы немного поэкспериментируете с утилитой grepи прочитаете

    документацию к ней, то найдете небольllП1е различия между регулярн ыми выражениями Питона и регулярными вы ражени ями, используемыми в g r e p. Например, gr e p не поддерживает непробельный символ '\S", так что придется использовать чуть более сложное обозначение "[л ]", означающее попросту любой символ, отличный от пробела.

      1. 1   2   3   4   5   6   7   8   9   ...   12


    написать администратору сайта