Strings em Python: Introdução
Tags: python, beginners, tutorial
Published: 2019-11-17 22:34:55

### Introdução

**Definição**: Uma **[String](https://en.wikipedia.org/wiki/String_(computer_science))** é tradicionalmente um tipo de dados que representa uma sequência de caracteres.

Um caracter é simplesmente um símbolo. Por exemplo, o idioma inglês possui 26 caracteres.

Caracteres podem ser **letras**, **dígitos**, **símbolos** ($, !, #, @), etc.

Os computadores originalmente não lidam com caracteres, eles lidam fundamentalmente com números (binários). Mesmo que vejamos caracteres em nossa tela, internamente eles são armazenados e manipulados como uma combinação de **0**'s e **1**'s.

A conversão de caracteres em números é chamada de codificação e o processo reverso é a decodificação. [ASCII](https://en.wikipedia.org/wiki/ASCII) e [Unicode](https://en.wikipedia.org/wiki/Unicode) são algumas das codificações populares usadas. Em Python, uma string é uma sequência de caracteres Unicode. O Unicode foi introduzido para incluir todos os caracteres em todos os idiomas e trazer uniformidade na codificação.

A figura a seguir nos mostra a Tabela ASCII:

![img](https://raw.githubusercontent.com/the-akira/Python-Iluminado/master/Imagens/ASCIITable.png)

Com a função **ord()** podemos obter o valor ASCII para um determinado caracter:

```python
ord('A') # 65
ord('X') # 88
ord('<') # 60
```

Contanto que permaneçamos no domínio dos caracteres comuns, haverá pouca diferença prática entre ASCII e Unicode. Mas a função **ord()** retornará valores numéricos para caracteres Unicode também:

```python
ord('∑') # 8721
ord('火') # 28779
```

Já o método **chr()** faz o inverso de **ord()**. Fornecido um valor numérico, ele retorna uma string representando este valor.

```python
chr(65) # 'A'
chr(88) # 'X'
chr(60) # '<'
chr(28779) # '火'
```

Existem diversos problemas no mundo real que envolvem as **strings**, podemos citar por exemplo:

- Criptografia e Descriptografia
- Análises de DNA
- Tradução de linguagens

### Fundamentos

Além dos números, **Python** é capaz de manipular **strings** com maestria, as strings podem ser expressas de diversas maneiras, podemos encapsular elas com aspas simples **('...')** ou também aspas duplas **("...")** ou até mesmo **("""...""")** para múltiplas linhas. Por exemplo:

```python
print('String é um elemento importante da programação')
print("Também podemos representá-las com aspas duplas")
print("""Podemos, até mesmo, representá-las com três aspas duplas, para textos grandes""")
```

Como podemos ver, **strings** podem ser impressas utilizando a função **print()**
Caso você queira usar palavras entre aspas na sua **string**, você deve usar \ **(contrabarra)** para dar *escape* nas aspas, caso contrário ocorrerá um erro:

```python
print("Podemos usar aspas dentro das \"strings\"")
print('Podemos usar aspas dentro das \'strings\'')
```

Ou até mesmo você pode **inverter** o uso das aspas:

```python
print("Dessa forma não há 'problema'")
print('Dessa forma não há "problema"')
```

### Índices de Strings

Assim como em diversas linguagens de programação, **strings** em **Python** são consideradas **arrays de bytes** que representam caractéres unicode, entretanto **Python** não tem um tipo de dados caracter. Caracteres únicos são simplesmente **strings** de tamanho 1. Para acessarmos elementos individuais das **strings**, utilizamos colchetes **[]**.

![img](https://raw.githubusercontent.com/the-akira/Python-Iluminado/master/Imagens/String.png)

```python
s = "Rafael"
print(s[0]) # Imprime a primeira letra do nome
print(s[-6]) # Imprime a primeira letra do nome

print(s[5]) # Imprime a última letra do nome
print(s[-1]) # Imprime a última letra do nome
```

Observe que foi utilizado a notação `s[0]`, isso porque o primeiro caracter começa na posição `0`, lembre que isso é muito comum nas linguagens de programação e estruturas de dados. Cada caracter na **string** é associado com um **índice** numérico, que é um inteiro representando a localização do caracter em uma determinada **string**.

Além disso, podemos formar **substrings** a partir de uma **string**.

```python
nome = "John Von Neumann"
```

Neste exemplo, selecionamos o caracter da posição 5 até 11 (não incluindo 12):

```python
print(nome[5:12]) # Von Neu
```

Podemos também reverter a string usando a seguinte notação:

```python
print(nome[::-1]) # nnamueN noV nhoJ
```

### Métodos em Strings

Um detalhe importante dentro do universo das **strings** é que podemos utilizar **[métodos](https://www.w3schools.com/python/python_ref_string.asp)** (funções especiais) para manipulalá-las.

Para compreendermos melhor estes métodos, vamos definir uma string para podermos testá-los:

```python
nome = " Meu nome é Dennis Ritchie "
```

O método **strip()** remove todos os espaços extras no começo e no fim da string:

```python
print(nome.strip()) # Meu nome é Dennis Ritchie
```

O método **len()** retorna o tamanho (comprimento) da string:

```python
print(len(nome)) # 27
```

O método **lower()** retorna a string em lower case (todos os caracteres se tornam minúsculos):

```python
print(nome.lower()) # meu nome é dennis ritchie
```

O método **upper()** retorna a string em upper case (todos os caracteres se tornam maiúsculos):

```python
print(nome.upper()) # MEU NOME É DENNIS RITCHIE
```

O método **swapcase()** retorna a string com caracteres uppercase convertidos para lowercase e vice-versa:

```python
print(nome.swapcase()) # mEU NOME É dENNIS rITCHIE 
```

O método **title()** retorna a string ao qual a primeira letra de cada palavra é convertida para uppercase e as demais letras pernanecem lowercase:

```python
print(nome.title()) # Meu Nome É Dennis Ritchie
```

O método **replace()** substitui a string que desejarmos por outra string especifica por nós via argumento:

- Primeiro informamos a string a ser substituída
- Segundo informados a nova string

```python
print(nome.replace("Dennis", "Ken")) # Meu nome é Ken Ritchie
```

O método **split()** separa a string em substrings caso haja um separador, nesse caso utilizamos o espaço (" ") e ele nos retorna uma lista de strings:

```python
print(nome.split(" ")) # ['', 'Meu', 'nome', 'é', 'Dennis', 'Ritchie', '']
```

O método **join()** retorna a string que resulta da concatenação dos objetos em um iterável separados por delimitador.

No exemplo a seguir, o delimitador é a string `','` e o iterável é uma lista de filósofos:

```python
filosofos = ['Kant', 'Kierkegaard', 'Nietzsche', 'Leibniz']

print(', '.join(filosofos)) # Kant, Kierkegaard, Nietzsche, Leibniz
print(' - '.join(filosofos)) # Kant - Kierkegaard - Nietzsche - Leibniz
```

O resultado é uma única string que consiste nos objetos da lista separados por um delimitador especificado por nós.

No próximo exemplo, iterável é especificado como um único valor de string. Quando um valor de string é usado como um iterável, ele é interpretado como uma lista dos caracteres individuais da string:

```python
list('aeiou') # ['a', 'e', 'i', 'o', 'u']
'|'.join('aeiou') # 'a|e|i|o|u'
```

O método **count()** retorna o número de ocorrências não sobrepostas de substring informada por nós:

```python
print("Ra Ra Ja Ra Ta".count("Ra")) # 3
```

O método **startwith()** retorna `True` se uma determinada string começa com um prefixo especificado, caso contrário, retorna `False`:

```python
print("existencialismo".startswith("exist")) # True
print("existencialismo".startswith("ismo")) # False
```

O método **endswith()** retorna `True` se uma determinada string termina com um sufixo especificado, caso contrário, retorna `False`:

```python
print("existencialismo".endswith("ismo")) # True
print("existencialismo".endswith("exist")) # False
```

O método **find()** pode ser usado para vermos se uma string contém uma substring informada e retorna o menor índice na string onde esta substring é encontrada:

```python
print('Amar, é encontrar a própria felicidade na felicidade alheia'.find('Amar')) # 0
print('Amar, é encontrar a própria felicidade na felicidade alheia'.find('é')) # 6
```

Os métodos de classificação de caracteres são capazes de classificar uma string baseado nos caracteres contidos nela. Vejamos alguns exemplos.

O método **isalnum()** retorna `True` se a string for não-vazia e todos os seus caracteres forem alfanuméricos (ou uma letra ou um número), e caso contrário, retorna `False`.

```python
print('xyz678'.isalnum()) # True
print('xyz#678'.isalnum()) # False
print(' '.isalnum()) # False
```

O método **isalpha()** retorna `True` se a string for não-vazia e todos os seus caracteres forem alfabéticos, caso contrário, retorna `False`.

```python
print('exemplo'.isalpha()) # True
print('exemplo 2'.isalpha()) # False
```

Para checarmos se uma string contém apenas dígitos, podemos utilizar o método **isdigit()**, ele vai retornar `True` se a string for não-vazia e todos os caracteres forem numéricos, e caso contrário, retornará `False`.

```python
print('33'.isdigit()) # True
print('a33z'.isdigit()) # False
print(''.isdigit()) # False
```

O método **isidentifier()** nos retorna `True` se uma determina string é um identificador válido de acordo com a definição da linguagem Python, caso contrário, retorna `False`.

```python
print('nome'.isidentifier()) # True
print('nome2'.isidentifier()) # True
print('2nome'.isidentifier()) # False
print('nome#'.isidentifier()) # False
```

Dessa forma podemos saber como definir uma variável corretamente.

Já o método **iskeyword()** é capaz de testar se uma determinada string corresponde à uma palavra-chave Python, este método é contido no módulo **keyword**, sendo então necessário importá-lo.

```python
from keyword import iskeyword

print(iskeyword("or")) # True
print(iskeyword("else")) # True
print(iskeyword("while")) # True
print(iskeyword("switch")) # False
```

O método **isprintable()** determina se uma string consiste inteiramente de caracteres imprimíveis. Ele retorna `True` se a string for vazia ou se todos os caracteres alfabéticos que ela conter forem imprimíveis, retorna `False` se ela conter pelo menos um caracter não-imprimível. Caracteres não-alfabéticos são ignorados.

```python
print('Gabriel\tFelippe'.isprintable()) # False
print('Gabriel Felippe'.isprintable()) # True
print(''.isprintable()) # True
print('x\ny'.isprintable()) # False
```

O método **isspace()** determina se uma string consiste de caracteres de **espaço em branco**, retornará `True` se a string for não-vazia e todos os caracteres forem de espaço em branco, caso contrário, retornará `False`.

```python
print(''.isspace()) # False
print('x'.isspace()) # False
print(' '.isspace()) # True
print('\t\n'.isspace()) # True
```

O método **isupper()** é capaz de verificar se todos os caracteres de uma string são uppercase:

```python
print("STRING".isupper()) # True
print("String".isupper()) # False
```

Já o método **islower()** é capaz de identificar se todos os caracteres de uma string são lowercase:

```python
print("String".islower()) # False
print("string".islower()) # True
```

### Formatando Strings

Vejamos agora como podemos usar métodos que modificam ou aprimoram o formato de uma string.

O método **center()** retorna uma string centralizada em um determinado comprimento especificado por nós via argumento, por padrão, o preenchimento consiste no caractere de **espaço** ASCII, por exemplo:

```python
'python'.center(20) # '       python       '
'python'.center(25,'.') # '..........python.........'
```

O método **expandtabs()** substitui cada caracter **tab** (`\t`) com espaços.

```python
'x\ty'.expandtabs() # 'x       y'
```

O método **ljust()** retorna uma string justificada à esquerda em um campo de comprimento especifica por nós via argumento, por padrão, o preenchimento consiste no caractere de **espaço** ASCII, por exemplo:

```python
'C++'.ljust(10) # 'C++       '
'C++'.ljust(10,'-') # 'C++-------'
```

O método **rjust()** retorna uma string justificada à direita em um campo de comprimento especifica por nós via argumento, por padrão, o preenchimento consiste no caractere de **espaço** ASCII, por exemplo:

```python
'Javascript'.rjust(20) # '          Javascript'
'Javascript'.rjust(20,'-') # '----------Javascript'
```

O método **zfill()** retorna uma cópia da string com preenchimento à esquerda com caracteres `'0'`, o comprimento é especificado por nós, por exemplo:

```python
'66'.zfill(4) # '0066'
```

Embora seja mais interessante para números, **zfill()** também funciona com caracteres:

```python
'letra'.zfill(7) # '00letra'
```

O método **format()** nos permite construir **strings** de uma maneira flexível:

```python
nome = "Rafael"
profissao = "Programador"

print("A profissão de {0} é {1}".format(nome,profissao))
# A profissao de Rafael é Programador
```

Criando um elemento [HTML](https://www.w3schools.com/html/html_intro.asp):

```python
tag = 'p'
texto = 'Este é um parágrafo'

sentenca = '<{0}>{1}</{0}>'.format(tag, texto)
print(sentenca) # <p>Este é um parágrafo</p>
```

Calculando um valor:

```python
valor = '1 GB é igual a {:,} bytes'.format(10**9)
print(valor) # 1 GB é igual a 1,000,000,000 bytes
```

Existe também a possibilidade de usarmos Códigos de Formatação.

**Inteiro**:

```python
print("{:d}".format(4)) # 4
```

**Binário**:

```python
print("{:b}".format(55)) # 110111
``` 

**Hexadecimal**:

```python
print("{:x}".format(15)) # f
```

**Lista**:

```python
print("{:}".format([20, 30])) # [20, 30]
```

Também podemos representar as **strings** de maneira similar ao estilo da linguagem **C**.

**String**:

```python
nome = "Alan"
amigo = "Jones"

print("%s é amigo de %s" %(nome,amigo))
# Alan é amigo de Jones
```

**Inteiro**:

```python
print("%d" % (4545)) # 4545
```

**Float**:

```python
print("%3.5f" % (3.123456789)) # 3.12346
print("%2.4f" % (3.123456789)) # 3.1235
```

### F-Strings

F-strings são um novo tipo de *string literals* introduzido na versão **[3.6](https://docs.python.org/3/whatsnew/3.6.html)** do Python. A **string** formatada é prefixada com a letra `f` e é similar à formatação de strings aceita por `format()`.

Vejamos exemplos:

```python
first_name = "Alan"
last_name = "Turing"

sentenca = f'Meu nome e {first_name.upper()} {last_name.lower()}'
print(sentenca) # Meu nome e ALAN turing
```

Observe que podemos também executar métodos com F-strings.

Além disso, podemos também utilizar **dicionários**:

```python
pessoa = {'nome': 'Muhammad', 'idade': 22}

sentenca = f'Meu nome é {pessoa["nome"]} e eu tenho {pessoa["idade"]} anos de idade'

print(sentenca)
# Meu nome é Muhammad e eu tenho 22 anos de idade
```

Ou até mesmo realizar operações matemáticas:

```python
calculo = f'4 vezes 11 é igual a {4 * 11}'
print(calculo) # 4 vezes 11 é igual a 44

for n in range(1,11):
    sentenca = f'O Valor é {n:02}'
    print(sentenca)
```

Para formatarmos datas precisaremos importar a biblioteca **datetime**:

```python
from datetime import datetime

nascimento = datetime(1991, 6, 6)

sentenca = f'O Nascimento é no dia {nascimento:%B %d, %Y}'

print(sentenca)
# O Nascimento é no dia June 06, 1991
```

### Convertendo para o Formato String

Para fazermos a conversão para uma string podemos utilizar os métodos `repr()` e `str()`:

```python
x = 10
y = [1, 3.14, 17, 13]

print(type(repr(x))) # <class 'str'>
print(type(str(y))) # <class 'str'>
```

### Escape Caracteres

**Strings** também são capazes de aceitar **Escape caracteres**:

| Carácter | Descrição      |
|---------|-----------------|
| \n      | nova linha      |
| \r      | carriage return |
| \s      | espaço          |
| \t      | tab             |
| \v      | tab vertical    |
| \e      | escape          |
| \b      | backspace       |

Vejamos um exemplos dos escape caracteres:

```python
print("Meu nome é\nGabriel")
print("\tOlá meu amigo")
```

### Operadores

Operadores Especiais:

| Operador | Descrição                                                      |
|----------|----------------------------------------------------------------|
| +        | concatenação, adiciona os valores                              |
| *        | repetição, concatena múltiplas cópias da mesma string          |
| in       | para verificarmos se determinado caracter existe na string     |
| not in   | para verificarmos se determinado caracter não existe na string |

Veja um exemplo dos operadores especiais:

```python
nome = "Carl"
sobrenome = "Sagan"

print(nome +" "+ sobrenome) # Concatena o nome e sobrenome
print(nome*10)              # Multiplica o nome por 10
print("C" in nome)          # Verifica se C está presente em nome e retorna True
print("C" not in nome)      # Verifica se C não está presente em nome e retorna False
```

É importante lembrarmos que **strings** são imutáveis, uma vez criada, não pode ser modificada. Para alterar uma **string** você deve primeiro construir uma nova string através da concatenação ou chamada de uma função e então re-atribuir à variável **string**.

O conteúdo de **strings** é bastante extenso e continuaremos vendo elas ao longo do guia, considere dar bastante importância a elas!