poprzedni temat | w górę | następny temat

Obsługa tekstów

Klasa str, unicodebasestring

Obiekty klasy str występującej w Python 2.x są napisami, które nie zawierają informacji na temat sposobu kodowania znaków spoza tradycyjnego zakresu ASCII. Z tego powodu, jeśli używamy klasy str, powinniśmy zawsze pamiętać, jakie jest kodowanie danego napisu.

Obiekt typu str otrzymujemy np. wczytując zawartość pliku lub pobierając dokument z sieci. Nie zawsze jesteśmy w stanie jednoznacznie określić, jakie jest kodowanie takiego dokumentu, dlatego jeśli możliwe są w takim przypadku różne kodowania, powinno być ono jawnie określone.

Obiekty klasy unicode przechowują tekst w wewnętrznej reprezentacji według standardu unicode — kwestia kodowania traci wtedy znaczenie. Aby uzyskać obiekt unicode, np. z napisu typu str, należy określić sposób kodowania znaków w danym napisie w momencie przekształcania go na unicode.

napis_unicode = u'Zażółć gęślą jaźń'
type(napis_unicode)
> unicode
napis_str_utf8 = napis_unicode.encode('utf8')
napis_str_utf8
> 'Za\xc5\xbc\xc3\xb3\xc5\x82\xc4\x87 g\xc4\x99\xc5\x9bl\xc4\x85 ja\xc5\xba\xc5\x84'
print napis_str_utf8 # terminal ustawiony na utf8
> Zażółć gęślą jaźń
print len(napis_unicode), len(napis_str_utf8)
> 17 26

Ostatnia instrukcja ujawnia, że obiekt str to tak naprawdę ciąg bajtów, traktowanych osobno — funkcja len() zwraca ich liczbę. W naszym przykładzie używamy kodowania utf8, więc potrzeba 26 bajtów do zakodowania powyższego napisu w tym kodowaniu. Obiekt unicode to ciąg znaków — len() zwraca ich liczbę.

Aby z napisu str otrzymać unicode, używamy metody .decode() podając jako argument sposób kodowania.

# str -> decode -> unicode
napis_str = 'Aj, pech! Struś dźgnął ćmę FBI! Koń lży wóz.'
napis_unicode = napis_str.decode('utf8')
napis_unicode
> u'Aj, pech! Stru\u015b d\u017agn\u0105\u0142 \u0107m\u0119 FBI! Ko\u0144 l\u017cy w\xf3z.'

# unicode -> encode -> str
napis_unicode = u'Dość błazeństw, żrą mój pęk luźnych fig.'
napis_str = napis_unicode.encode('windows-1250')
napis_str
> 'Do\x9c\xe6 b\xb3aze\xf1stw, \xbfr\xb9 m\xf3j p\xeak lu\x9fnych fig.'

Obie klasy strunicode dziedziczą po klasie basestring. Nie da się utworzyć obiektu klasy bezpośrednio basestring — używamy jej tylko do sprawdzania, czy jakiś obiekt jest tekstem.

isinstance(napis_str_utf8, basestring)
> True
isinstance(napis_unicode, basestring)
> True

Formatowanie napisów

Klasy strunicode mają bogaty zestaw metod manipulowania tekstem.

napis = u'   Ala   ma   kota.   '
napis.strip()
> u'Ala   ma   kota.'
napis.rstrip()
> u'   Ala   ma   kota.'
napis.strip().center(30)
> u'       Ala   ma   kota.       '
u'abcde'.capitalize()
> u'Abcde'
napis.lower().islower()
> True
napis = napis.strip()
napis.startswith('Ala')
> True
napis.rjust(30)
> u'              Ala   ma   kota.'
napis.ljust(30)
> u'Ala   ma   kota.              '
napis.swapcase()
> u'aLA   MA   KOTA.'
napis.title()
> u'Ala   Ma   Kota.'
napis.istitle()
> False
napis.title().istitle()
> True
'kot' in napis
> True
'pies' not in napis
> True
napis.replace('kota', 'psa').replace('Ala', 'Adam')
> u'Adam   ma   psa.'
'klucz: wartosc z: dwukropkiem, przecinkiem itd.'.partition(': ')
> ('klucz', ': ', 'wartosc z: dwukropkiem, przecinkiem itd.')
'%(miasto)s/%(miasto)s/%(ulica)s' % {
   'miasto': 'Lublin',
   'ulica': 'Akademicka',
}
> 'Lublin/Lublin/Akademicka'

Wyrażenia regularne

Wyrażenia regularne pozwalają wyszukiwać i wyodrębniać fragmenty tekstu z większej całości. Do ich konstrukcji używa się specyficznej składni. Poniższy przykład pokazuje, jak wyłuskać wszystkie adresy e-mail z zadanego tekstu.

import re

regex_email = re.compile(
  r'''(?P<adres>
    (?P<login>[\w+.]+)      # login, np. m.j.panczyk+umcs.pl
    @                       # znak @
    (?P<domena>\w+(\.\w+)+) # domena, np. gmail.com
  )''',
  re.IGNORECASE | re.VERBOSE
)
# regex_email to obiekt skompilowanego wyrażenia regularnego

tekst = u'Michał Pańczyk <moj.email@umcs.lublin.pl>, "moj_drugi_mail@domena.pl"'
for match_object in regex_email.finditer(tekst):
      print match_object.groupdict()
> {'domena': u'umcs.lublin.pl', 'login': u'moj.email', 'adres': u'moj.email@umcs.lublin.pl'}
> {'domena': u'domena.pl', 'login': u'moj_drugi_mail', 'adres': u'moj_drugi_mail@domena.pl'}

Litera r przed literałem tekstowym będącym argumentem funkcji compile() powoduje, że znak odwrotnego ukośnika \ traci swoje znaczenie.

print r'\n'
> \n

Moduł re zawiera dużo więcej przydatnych funkcji, o których można przeczytać w dokumentacji.

XKCD: Regular Expressions

Przykładowe formaty serializacji danych

JSON

Do obsługi formatu JSON w Pythonie możemy użyć modułu json.

import json

slownik = {
  'data': 'abcdef',
  'cnt': "10",
  'items':[1,2,3,4],
}

json_str = json.dumps(slownik)
json_str
> '{"items": [1, 2, 3, 4], "cnt": "10", "data": "abcdef"}'

json.loads(json_str)
> {u'cnt': u'10', u'data': u'abcdef', u'items': [1, 2, 3, 4]}

pickle

pickle jest modułem, który umożliwia serializację obiektów do wewnętrznego formatu Pythona. Podobnie, jak moduł json, moduł pickle zawiera m.in funkcje loads() oraz dumps().

Zamiast pickle, możesz użyć modułu cPickle, który jest zaimplementowany w C i działa szybciej.

YAML

Analogicznie do dwóch powyższych formatów danych, możemy używać YAML, przy czym moduł yaml nie jest umieszczony w standardowej bibliotece.

base64

Do obsługi base64 możemy użyć modułu base64.

import base64

base64.encodestring('Ala ma kota')
> 'QWxhIG1hIGtvdGE=\n'
base64.decodestring('QWxhIG1hIGtvdGE=\n')
> 'Ala ma kota'

Zadania

  1. Napisz funkcję, która dostaje jako parametry napis i liczbę width. Funkcja ma wypisać napis na standardowe wyjście w ten sposób, żeby w każdej linii było co najwyżej width znaków. Funkcja może dzielić słowa tylko o długości większej od width.

  2. Zmodyfikuj powyższe zadanie tak, by wypisywany tekst był wyśrodkowany (w obrębie zadanych width miejsc na ekranie).

  3. Napisz program, który z zadanego parametrem pliku tekstowego wypisze na standardowe wyjście wszystkie poprawne adresy IP (ver. 4) — każdy w osobnej linii.

  4. Napisz funkcję, która dostaje numer PESEL (napis lub liczbę) i dokonuje jego walidacji.

  5. Napisz program, który dla podanego pliku tekstowego wyszukuje w nim wszystkie frazy postaci: Anna Nowak PESEL:02271409862. Dla każdej znalezionej frazy z poprawnym numerem PESEL program ma wypisać imię, nazwisko i rok urodzenia.

  6. Napisz program, który dostaje jako parametry dwie nazwy plików. Pierwszy plik np. plik.json ma zawierać dane w formacie json. Program ma zapisać do drugiego pliku w formacie pickle odkodowane wcześniej dane.

poprzedni temat | w górę | następny temat