Програмиране с Python: Модули
Author: Димитър Димитров, Стефан Кънев и Николай Бачийски

# Файлове, ескимоси и unicode

### „ Програмиране с Python“, ФМИ

### Стефан Кънев & Николай Бачийски

#### 02.04.2008г.

# Файлове

- Именувани обекти
- Поддържат се на ниво операционна система

# Отваряне на файлове в Python

    >>> out = open('/tmp/spam', 'w')
    >>> inp = open('cow_names', 'r')
    >>> inp = open('cow_names')
    >>> inp = open('logfile', 'a')
    >>> inp = open('dingdong', 'r+')

# Четене от файлове

    >>> inp.readline()
    'I am name number 1\n'

    >>> lines = inp.readlines()
    ['I am name number 1\n', 'I am name number 1, stupid!\n',→
    'I am name number 2, or 3!\n']

    >>> inp.read()
    'I am name number 1\nI am name number 1, stupid!\n→
    I am name number 2, or 3!\n'

    >>> inp.read(4)
    'I am'

    >>> sys.stdin.read(4)
    'I am'

    >>> inp.close()

# for, наш приятел

    >>> for line in open('cow_names'):
    	print 'I want a %d-tone %s!' %
    		(random.randint(1, 4), line.strip())

    I want a 4-tone Gregorius!
    I want a 1-tone Calvin!
    I want a 3-tone Shlyushltushlyu!
    I want a 3-tone Yabadaduuuu!

# Трябва и да се дава, не само да се взема

    >>> print >>out, "Another One Bites the Dust"

    >>> out.write("Another One Bites the Dust")

    >>> out.writelines(["Gargantua\n", "42 is my lucky birth date!\n"])

    >>> print >>sys.stdout, "Bingo was here!"

    >>> out.flush()

    >>> out.close()

# От хартията в компютъра

- ASCII
  - цял байт
  - 0–31 — контролни кодове
  - 32–127 — символи (a-z, A-Z, 0-9, препинателни знаци)
  - 128–255 — вятър ги вее на бял кон

# От САЩ в света

- ASCII не обхваща други азбуки
- различни кодови таблици по различен начин използват пространството 128–255
  - latin1 (ISO-8859-1) — добавя символи като ß, ù, ¶
  - windows-1252 (cp1252) — подобно на latin1, начало на Miscrosoft Codepages
  - за всяка азбука/страна поне по още една кодова таблица
  - най-разпространена за кирилица — windows-1251

# Unicode

> Unicode provides a unique number for every character,
> no matter what the platform,
> no matter what the program,
> no matter what the language.

- около 100 хиляди символа (code points), основните се събират в 65536 (216)
- всеки символ (code point) си има номер, доста и име:
- Ж U+0416 CYRILLIC CAPITAL LETTER ZHE
- първите 256 са като в latin1 за обратна съвместимост
- урежда подредба на символите
- не урежда кодирането им в байтове!

# Представяния на Unicode

- представяне = кодировка = encoding != charset
- UTF-16: 2 байта на code point
- UTF-16 BE/LE, BOM
- UTF-8

      					От
      					До
      					Двоична поредица по байтове

      					000000
      					00007F
      					0xxxxxxx

      					000080
      					0007FF
      					110xxxxx 10xxxxxx

      					000800
      					00FFFF
      					1110xxxx 10xxxxxx 10xxxxxx

      					010000
      					10FFFF
      					11110xxx 10xxxxxx 10xxxxxx

# UTF-8

- съвпада с ASCII представянето до 127
- разширяем до безкрайност
- неконстантно индексиране
- азиатските символи са 3+ байта

# Unicode и Python

`str` с/у `unicode`

    >>> s = open('cow_names').read()
    >>> s # поредица от байтове
    '\xd0\xbf\xd0\xb8\xd0\xbb\xd0\xb5'
    >>> u = unicode(s)
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128)
    >>> u = unicode(s, 'utf8') # същото като u = s.decode('utf8')

    >>> len(s), len(u)
    (8, 4)
    >>> s[0], u[0]
    ('\xd0', u'\u043f')
    >>> ord(s[0]), ord(u[0])
    (208, 1087)

# Създаване на unicode низове

- `u = bytestring.decode(encoding)`
- `u = unicode(bytestring, encoding)`
- литерали тип `\uxxxx`: u'\u03bb' → λ
- истински литерали `λ`, само ако сте поставили коментар като `# -*- coding: encoding -*-`

# Изход чрез unicode низове

- Файловете в Python по подразбиране работят с ASCII

-     >>> out = open('cow_names', 'w')
      >>> print >>out, u'баба'
      UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3:→
       ordinal not in range(128)

      >>> print >>out, u'баба'.encode('utf8')
      >>> print >>out, u'баба'.encode('cp1251')

# Магията, наречена codecs

    >>> out = codecs.open('cow_names', 'w', encoding='utf8')
    >>> out.write(u'баба')
    >>> out.close()
    >>> inp = codecs.open('cow_names', 'r', encoding='utf8')
    >>> inp.readline()
    u'\u0431\u0430\u0431\u0430'

# Още въпроси?

- Страница на курса: http://fmi.py-bg.net/
- Форуми на курса: http://fmi.py-bg.net/forums/