Textos
Caracteres
Agora sim, vamos falar do último dos 4 tipos primários que abordaremos que é o tipo usado para armazenar texto.
Tudo o que você aprendeu até agora sobre protocolos e métodos especiais também se aplica aos textos, mas os textos tem uma pequena particularidade, eles são formados por caracteres.
>>> chr(65)
A
>>> chr(66)
B
>>> chr(67)
C
Portanto, o texto "ABC"
internamente contém um conjunto de 3 caracteres nas
suas respectivas posições na tabela de caracteres.
Existem várias tabelas de caracteres usadas na computação, as mais importantes
são a ascii
e utf8
.
A tabela ASCII
possui 128 posições, ou seja, vai do 0 ao 127 e em cada
posição armazena apenas um caractere. Ela tem os caracteres básicos da lingua
inglesa e como pode perceber ela não considera acentuação ou caracteres
especiais de outros idiomas como Russo ou Mandarim.
Quando a computação globalizou foi preciso mudar de tabela e adotar uma maior
que pudesse comportar uma quantidade universal de caracteres e também os
emojis
que se tornaram parte da comunicação moderna.
A tabela unicode
de 8 bits
- utf8 atualmente tem 120 mil caracteres.
Nesta tabela além da tabela ASCII padrão, a partir da posição 128
temos
acentuação e subtabelas para símbolos e emojis.
Na tabela ASCII
cada caractere ocupava menos de 1 byte (7 bits) e por isso que
A
é 65
que na tabela é 1000001
(7 dígitos).
Já na tabela unicode cada caractere pode ser formado por mais de um byte, por
exemplo, uma letra com acento à ocupa 2 bytes 11000011 10000011
na tabela.
E alguns emojis como o 🍉 ocupam 4 bytes 11110000 10011111 10001101 10001001
Durante a programação com Python nós iremos considerar que os nossos textos
utilizam os caracteres disponíveis na tabela utf8
e em alguns raros casos no
Python3 teremos que explicitamente fazer operações de encode
e decode
a partir de um texto ascii
para utf-8
.
# variável
fruit = "🍉"
# para transmitir este texto ou gravar em um arquivo
# ou banco de dados pode ser necessário encodificar ele.
>>> fruit.encode("utf-8")
b'\xf0\x9f\x8d\x89'
Esse valor b'\xf0\x9f\x8d\x89'
é um objeto do tipo bytes
e repare que ele
tem 4 elementos separados por \
cada um deles é um dos bytes que formam a 🍉.
A operação contrária, por exemplo, quando lermos de um arquivo ou banco de
dados que não suporta utf8
será com o decode
.
melancia_em_bytes = b'\xf0\x9f\x8d\x89'
>>> melancia_em_bytes.decode("utf-8")
'🍉'
O objeto ali iniciado por b''
é uma sequência de bytes em formato
hexadecimal. A título de curiosidade
f0 = 11110000 9f = 10011111 8d = 10001101 89 = 10001001
Que são os 4 bytes que formam o caractere 🍉 e você pode verificar isso no Python com cada um dos valores da lista:
>>> hex(0b11110000)
'0xf0'
Em Python números começados com 0b
são binários e 0x
são hexadecimais.
Strings, ou cadeia de caracteres
Até aqui falamos de caracteres isolados como A
, B
, 🍉
, mas ao programar
também precisaremos juntar esses caracteres para formar palavras e frases,
quando criamos uma variável do tipo texto em Python ele através da presença de
aspas sejam elas simples '
ou duplas "
armazena esse valor numa classe do
tipo str
e este tipo de dado pode armazenar um ou mais caracteres.
>>> nome = "Bruno"
type(nome)
E como você já deve ter imaginado aqui armazenamos cada uma das letras
B
, r
, u
, n
, o
com seus respectivos bytes e sequência posicional
num único
objeto. (a palavra “string” significa corda, cadeia ou corrente),
A palavra "Bruno"
é uma lista contendo em cada posição um caractere da tabela
utf8
.
>>> list(bytes(nome, "utf-8"))
[66, 114, 117, 110, 111]
>>> chr(66)
'B'
>>> chr(114)
'r'
>>> chr(117)
'u'
>>> chr(110)
'n'
>>> chr(111)
'o'
Bem, para guardar o nome "Bruno" você mais uma vez não precisa se preocupar com esses detalhes todos, basta fazer nome = "Bruno" e usar este texto para efetuar as operações que você desejar, porém, é muito útil saber como o objeto está implementado.
current_language = os.getenv("LANG", "en_US")[:5]
Sabendo que current_language
poderia ter o valor en_US.utf8
nós usamos o
protocolo Sliceable
do objeto str
para fatiar o texto e pegar somente os
primeiros 5 caracteres.
>>> "en_US.utf8"[:5]
'en_US'
>>> "Bruno"[2]
'u'
>>> "Python"[0]
'P'
O tipo str
possui a maioria das características que já abordamos nos outros
tipos de dados e uma abundância de protocolos implementados, vamos ver
alguns.
# Sliceable (pode ser fatiado)
>>> "Bruno"[1]
'r'
# que internamente invoca o método `__getitem__`
>>> "Bruno".__getitem__(1)
'r'
# Addible (pode ser adicionado a outro texto)
# Essa operação se chama "Concatenação"
>>> nome = "Bruno"
>>> sobrenome = "Rocha"
>>> nome + " " + sobrenome
'Bruno Rocha'
# que internamente invoca o método `__add__`
>>> nome.__add__(" ".__add__(sobrenome))
'Bruno Rocha'
# Multipliable (que pode ser multiplicado)
>>> "Bruno" * 5
'BrunoBrunoBrunoBrunoBruno'
# Iterable (que pode ser iterado/percorrido)
>>> for letra in "Bruno":
... print("-->" + letra.upper())
-->B
-->R
-->U
-->N
-->O
# Internamente o statement `for` invoca o método `__iter__`
>>> iterador = "Bruno".__iter__()
>>> next(iterador)
'B'
>>> next(iterador)
'r'
Além disso, o tipo str
também oferece muitos métodos públicos, que nós
podemos usar explicitamente e que são muito úteis.
>>> "Bruno".upper()
'BRUNO'
>>> "BRUNO".lower()
'bruno'
>>> "bruno rocha".capitalize()
'Bruno rocha'
>>> "bruno rocha".title()
'Bruno Rocha'
>>> "bruno rocha".split(" ")
['bruno', 'rocha']
>>> "bruno".startswith("b")
True
>>> "bruno".endswith("b")
False
>>> "bruno rocha".count("o")
2
>>> "bruno rocha".index("c")
8
>>> "bruno rocha"[8]
'c'
E também algumas coisas que podemos fazer com qualquer objeto sequencial do Python:
>>> len("Bruno Rocha")
11
>>> sorted("Bruno Rocha")
[' ', 'B', 'R', 'a', 'c', 'h', 'n', 'o', 'o', 'r', 'u']
>>> list(reversed("Bruno Rocha"))
['a', 'h', 'c', 'o', 'R', ' ', 'o', 'n', 'u', 'r', 'B']