# Textos e Strings
Dalton Serey Originalmente, a computação era predominantemente sobre números. De fato, _computar_ é sinônimo de _calcular_. Nos dias atuais, contudo, uma parte crescente dos dados processados e das _computações_ lidam com sobre _textos_ e _símbolos_ não numéricos em geral. Nesta lição, veremos as facilidades de Python para manipular dados textuais. ## Um exemplo Considere o programa no _repl_ abaixo. Execute-o e investigue como funciona e qual você espera que seja o valor final de cada uma das variáveis. ## Análise do programa Se você já leu as atividades sobre números e variáveis, este programa deve ser simples de entender. A principal diferença está nos tipos de dados manipulados. Ao invés de números, o programa manipula dados textuais. O programa consiste em três _blocos de código_ (observe que cada bloco é separado dos demais por uma linha em branco). O primeiro, define duas variáveis nomeadas `saudacao_inicio` e `saudacao_fim`, nomes que certamente se referem ao fato de estarem vinculadas aos textos que iniciam e terminam as mensagens de saudação que se quer compor. Em seguida, na segunda parte, são definidas três variáveis com os _nomes_ de pessoas para os quais se quer preparar as mensagens de saudação e despedida. Finalmente, na terceira parte, são definidas as variáveis, `saudacao1`, …, `adeus3`, definindo-as a partir de _expressões_. Entendo que as partes 1 e 2 dispensem maiores explicações. O único aspecto a observar é que do lado direito de cada um desses comandos de _atribuição_ há um literal de _string_. Mais abaixo detalhamos como são definidos os literais de strings, por ora, basta saber que é delimitado por aspas `"`. Assim, a string de fato armazenada na variável `saudacao_inicio` é `Oi, `, incluindo este espaço final, mas deixando de fora as aspas usadas. Elas são apenas parte do programa, usadas para delimitar o dado textual. A terceira parte do código merece um pouco mais de atenção. O lado direito dessas atribuições não são meros literais de _strings_, mas expressões para calcular novas _strings_ em _tempo de execução_. Isto quer dizer que, quando o programa for executado, Python deve _avaliar_ (processar) as expressões e calcular novas _strings_ a partir daquelas definidas explicitamente através dos literais. Tomemos a primeira atribuição do terceiro bloco. ``` saudacao1 = saudacao_inicio + p1 + saudacao_fim ``` Quando essa linha for executada, as variáveis do lado direito, `saudacao_inicio`, `p1` e `saudacao_fim`, já terão sido definidas e seus literais são, respectivamente: `"Oi, "`, `"Fulano"` e `". Bom dia."`. Resta-nos saber qual o significado do operador `+` nesse contexto. Se os operandos fossem números, o operador `+` seria interpretado como uma soma numérica. Contudo, os valores das variáveis são do tipo `str` que não é numérico. Para entender como Python interpreta esse operador, basta ver o resultado da operação. O valor final da variável `saudacao1`, que pode ser visto no _repl_ confirma o que poderíamos suspeitar. O operador `+` será interpretado como uma _concatenação_, quando os operandos forem _strings_. Concatenação é o nome dado à operação de criar uma nova _string_ a partir de duas ou mais _strings_, justapondo-as (ou colando-as) para formar uma nova _string_. ## Strings e Literais De forma semelhante ao que ocorre com números, linguagens de programação precisam de uma representação interna apropriada para armazenar dados textuais. Historicamente, linguagens de computador chamam esse tipo de dado de _string_, que significa _cadeia_, _sequência_ ou _corrente_. Python não é diferente e também tem, portanto, um tipo _string_ (internamente, contudo, o tipo é chamado de `str`). **Léxico** Perceba, contudo, que Python, assim como outras linguagens, não podem tratar qualquer sequência de caracteres como dado textual. Se isso fosse feito, o interpretador não teria como diferenciar o dado textual dos comandos do programa. Por isso, literais de strings devem obedecer às regras de escrita de _strings_. As regras são simples, mas é importante conhecê-las. _Strings simples_ são delimitadas por aspas duplas `"` ou por aspas simples `'`. Assim, são literais válidos de strings: `'Oi'` ou `"Oi"`. Não são literais de _strings simples_ trechos em que as aspas de início e fim não fechem adequadamente ou que não tenham as aspas. Por exemplo, estes textos **não são literais válidos** de _strings_: `"Oi'`, `'Oi"` ou ainda `Oi`. Literais de _strings longas_, em particular se tiverem múltiplas linhas, são delimitadas por três aspas simples (`'''`) ou três aspas duplas (`"""`). Como disse antes, são usadas para dados textuais longos que possivelmente incluem textos com múltiplas linhas. Veja o exemplo abaixo. ```python msg = """Caro aluno, Este é um exemplo de literal de string contendo múltiplas linhas. Observe que ele se inicia logo após a sequência com três aspas e só acaba quando a segunda sequência de três aspas for encontrada. []s Dalton """ outra = "esta é outra string" ``` ### Codificações Internamente, _strings_ precisam ser representadas por bits e bytes, como tudo mais no computador. Para isso, precisamos de alguma forma de _codificação_ (ou _encoding_). A codificação mais famosa na computação é a conhecida [ASCII](https://en.wikipedia.org/wiki/ASCII) (_American Standard Code for Information Interchange_). Essa codificação, contudo, usa apenas 7 bits e inclui apenas os caracteres básicos necessários para o inglês. Isso significa que não inclui os caracteres acentuados que a maioria dos idiomas derivados do Latin precisa, por exemplo. Muito menos outros caracteres acentuados, como caracteres gregos, cirílicos, etc. Uma segunda codificação bastante famosa e até bastante usada hoje em dia é a [ISO 8859-1](https://en.wikipedia.org/wiki/ISO/IEC_8859-1) que também é conhecida como Latin1. Ela pode ser vista como uma das codificações que estendem ASCII (há várias, contudo) e usam 8 bits (um byte moderno, portanto) e permite 256 representações. Isso permite incluir a maioria dos caracteres necessários nos idiomas em uso na europa e na américa latina. > No Brasil, a ABNT também definiu uma extensão que chegou a ser > bastante usada nos computadores e impressoras fabricadas por > aqui anos > 80: o [BraSCII](https://en.wikipedia.org/wiki/BraSCII). > Por ser mais abrangente e permitir compatibilidade mais > universal, o Brasil e demais países de idiomas latinos > terminaram optando pelo ISO 8859-1 como codificação padrão. **Unicode e UTF-8** Mais recentemente, uma nova codificação vem sendo usada e tem se tornado o padrão, de fato, em praticamente qualquer máquina: o [UTF-8](https://en.wikipedia.org/wiki/UTF-8). Trata-se de uma codificação de tamanho variável em que, ao contrário das anteriores mencionadas acima, cada caractere pode ser representado por 1 ou múltiplos bytes. Essa flexibilidade permite um número variável (crescente, obviamente) de caracteres. É por isso, que o conjunto de caracteres representado é definido de forma independente. O conjunto de caracteres codificado por UTF-8 é o [Unicode](https://en.wikipedia.org/wiki/Unicode) que tem por propósito capturar **todos** os caracteres usados no mundo. Isso inclui todas as linguagens, inclusive linguagens mortas, caracteres gráficos, emojis, símbolos matemáticos, etc. UTF-8 também pode ser visto como uma extensão de ASCII. É por isso que os caracteres básicos, sem acentuação são representados diretamente por um único byte. Internamente, Python usa Unicode para representar caracteres. Isso significa que você pode usar praticamente qualquer caractere em seus programas. Contudo, lembre que para isso, pode ser necessário armazenar mais de 1 byte por caractere. Vejamos como isso pode ser confirmado em Python. Em um _shell_ Python, digite os comandos abaixo: ```python s1 = "casa" s2 = "você" len(s1) len(s2) ``` A função `len()` permite identificar o comprimento de uma sequência de dados em Python. Neste caso, a estamos usando para investigar quantos caracteres têm as strings ligadas às variáveis `s1` e `s2`. Python deve indicar 4 caracteres, já que esse é o número de letras ou caracteres em cada string. Agora, vejamos uma segunda operação: `.encode()`. Esta função permite codificar uma string, usando a codificação desejada. Neste caso, se não colocarmos nada nos parênteses, Python usará a codificação padrão que é UTF-8. Observe que Python irá mostrar um literal parecido com o de _strings_, mas precedido de um `b`. Esse é o literal de sequências de bytes. Isso permite que diferenciemos strings (sequências) de caracteres de strins (sequências) de bytes puros. Abaixo vemos o que Python imprimirá ao invocarmos a função `.encode()` de `s1` (observe que esta função é invodada de forma diferente, usando um ponto (`.`) entre o nome da variável e o nome da função: trata-se de um _método_). No comando seguinte, combinamos `len()` e `.encode()` para saber quantos bytes a codificação da string `casa` precisará. ```python >>> s1.encode() b'casa' >>> len(s1.encode()) 4 ``` A saída acima indica que para codificar os caracteres de `casa` em UTF-8, Python precisará de 4 bytes. Vejamos agora o que ocorre com a palavra `você` armazenada em `s2`. ```python >>> s2.encode() b'voc\xc3\xaa' >>> len(s2.encode()) 5 ``` Acima vemos que Python precisará de 5 bytes para codificar a palavra `você`. E também vemos byte a byte a codificação da palavra. Observe que `v`, `o` e `c` são codificados diretamente pelos bytes que correspondem a essas letras na tabela ASCII. É por isso que o literal de bytes de Python apresenta esses bytes como letras (lembre, na verdade, são apenas bits mesmo). Já o caractere `ê` requer dois bytes, representados no literal por `\xc3\xaa`. Observe aqui que há duas subsequências iniciada por um `\x`, seguidas de dois caracteres hexadecimais. Cada um deles corresponde a um byte. E os dois juntos é que codificam o caractere `ê`, em UTF-8. > Sugestão de exercício. Crie um arquivo de texto contendo apenas > a palavra `você` (certifique-se, se puder, que o editor está > usando UTF-8 para codificar o arquivo). No terminal, use o > comando `xxd` para imprimir os bytes do arquivo. Você verá que > a mesma codificação será usada e você deve ver os bytes (em > hexadecimal) de cada um dos caracteres: `76` para o `v`, `6f` > para o `o`, `63` para o `c` e, por fim, `c3` e `aa` para o `ê`. > Lembre que, se o editor for bom, ele deve ainda incluir o byte > `0a` que corresponde ao Enter (ou newline) para indicar o fim > da linha.