Introdução a dados textuais no Python

Essa é uma aula de introdução à manipulação de dados textuais, daqui em diante chamados de strings, com foco em expressões regulares (regex). Expressões regulares são úteis pois strings, geralmente, contêm informações não estruturadas e regex é uma linguagem concisa para descrever e manipular padrões em strings.

Para tratar strings utilizaremos as funções básicas do Python e as bibliotecas re e pandas:


import re
import pandas as pd

Você já aprendeu previamente a criar objetos que representam textos, vamos criar alguns:


texto1 = "Essa é uma string"
texto2 = 'Para incluir "aspas duplas" em uma string deve-se utilizar aspas simples'
print(texto1)

# Essa é uma string

print(texto2)

# Para incluir "aspas duplas" em uma string deve-se utilizar aspas simples

Escapando caracteres especiais

Para inserir outros caracateres especiais em uma string é necessário utilizar a contrabarra para "escapar" o caracter, assim o Python não gera um erro ou entende o caracter de maneira inesperada. Exemplos:

 
print("string com \"aspas\" dentro")

# string com "aspas" dentro

 
print("c:\users\fernando") # gera um erro pois a "\" é um caracter especial

# (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \uXXXX escape (<string>, line 1)

 
print("c:\\users\\fernando") # adicione uma contrabarra para escapar uma contrabarra

# c:\users\fernando

Pense nessa contrabarra como uma instrução interna do Python dizendo para — quando esse objeto for salvo em um arquivo de texto ou usado como uma legenda em um gráfico, por exemplo — incluir o caracter especial ao usar a string em um trecho de código adiante. Note também que a representação impressa da string não é a mesma que a própria string.

Como contar caracteres?

A função len() informa o número de caracteres em uma string e Series.str.len() em uma pandas Series:

 
len("c:\\Win") # contrabarra não conta

# 6

pd.Series(["c:\\Win", "Análise Macro", "Fernando"]).str.len()

 

# 0 6
# 1 13
# 2 8
# dtype: int64

Como combinar strings?

Para concatenar duas ou mais strings use o +:

txt1 = "Última atualização"
txt2 = pd.to_datetime("today").ctime()
txt1 + ": " + txt2

# 'Última atualização: Wed Sep 11 09:20:50 2024'

E para concatenar strings utilizando um separador use join(), seguindo a sintaxe "separador".join(["texto 1", "texto 2"]):
txt3 = ["a", "b", "c", "d", "e"]
", ".join(txt3)
# 'a, b, c, d, e'

Por fim, em um exemplo mais avançado, para concatenar duas listas de strings elemento a elemento, primeiro combine os elementos tal como [(lista_X[0], lista_Y[0]), (lista_X[1], lista_Y[1]), ..., (lista_X[n], lista_Y[n])] com a função zip() e em seguida itere join() sobre este resultado:
txt4 = ["1", "2", "3", "4", "5"]
list(map("-".join, zip(txt3, txt4)))

# ['a-1', 'b-2', 'c-3', 'd-4', 'e-5']
Este processo é muito mais simples ao trabalhar com pandas Series:

pd.Series(txt3) + "-" + pd.Series(txt4)

 

# 0 a-1
# 1 b-2
# 2 c-3
# 3 d-4
# 4 e-5
# dtype: object

Como filtrar strings?

Para extrair partes de uma string podemos utilizar o índice dos caracteres da mesma ("string"[indice]):

texto1[<span class="hljs-number">0</span>] <span class="hljs-comment"># 1º caracter</span>

# 'E'

texto1[0:6] # do 1º caracter até o 5º caracter, ou seja inicio:fim (fim não incluso)

# 'Essa é'

texto1[-1] # valores negativos contam de trás pra frente (último caracter)

# 'g'

texto1[-3:-1] # do antepenúltimo ao penúltimo

# 'in'

texto1[-3:] # do antepenúltimo ao último

# 'ing'

Em pandas Series o procedimento é semelhante com str.slice():

pd.Series([texto1, texto2]).str.slice(start = -1)

 

# 0 g
# 1 s
# dtype: object
pd.Series([texto1, texto2]).str.slice(stop = 5)
# 0 Essa
# 1 Para
# dtype: object

 

pd.Series([texto1, texto2]).str.slice(start = -3, stop = -1)
# 0 in
# 1 le
# dtype: object

Caixa alta, caixa baixa e sentença

A função lower() permite converter a string para letras minúsculas:

texto2.lower()

# 'para incluir "aspas duplas" em uma string deve-se utilizar aspas simples'

A função upper() permite converter a string para letras maiúsculas:

texto2.upper()

# 'PARA INCLUIR "ASPAS DUPLAS" EM UMA STRING DEVE-SE UTILIZAR ASPAS SIMPLES'
A função capitalize() permite converter a string para uma sentença (primeira letra maiúscula):

texto2.upper().capitalize()

# 'Para incluir "aspas duplas" em uma string deve-se utilizar aspas simples'

Padrões de correspondência com regex

Regex é uma linguagem que permite descrever padrões em strings. É difícil e demorado para entender (não é uma linguagem humana), mas depois de algum treinamento notamos que é um recurso extremamente útil. Vamos aprender sobre regex de uma forma intuitiva e didática primeiro, depois avançamos para exemplos práticos.

Para essa primeira parte definimos uma função para visualizar um padrão de uma regex em um texto (você já aprendeu a definir funções, a única novidade aqui é a função re.finditer(), sobre a qual abordaremos adiante):

# Função para visualizar padrão em um texto
def str_view(texto, regex):
padroes = list(re.finditer(regex, texto))
if padroes:
for p in reversed(padroes):
inicio = p.start()
fim = p.end()
texto = texto[:inicio] + "<" + texto[inicio:fim] + ">" + texto[fim:]
else: 
texto = ""
return texto

O padrão mais simples é a busca por um padrão exato em uma string, por exemplo:

txt5 = ["maça", "banana", "ameixa"]
str_view(txt5[2], "am")

# '<am>eixa'

str_view() é uma função apenas didática que serve para visualizar um padrão em uma string. Aqui procuramos pelo padrão "am" e a função destaca este padrão nos elementos (se encontrado) com os símbolos <>.

Tornando o padrão procurado um pouco mais complexo, podemos usar o "." para procurar por qualquer caracter (antes e depois do "a"):

str_view(txt5[<span class="hljs-number">0</span>], <span class="hljs-string">".a."</span>)

# '<maç>a'

list(map(lambda x: str_view(x, ".a."), txt5)) # iterando para todos os items da lista

# ['<maç>a', '<ban>ana', '']

Para procurar por um padrão no começo ou no final de uma string utilize as âncoras:

  • ^ procura por padrão no começo da string;
  • $ procura por padrão no final da string.

Exemplos:

list(map(<span class="hljs-keyword">lambda</span> x: str_view(x, <span class="hljs-string">"^a"</span>), txt5))

# ['', '', '<a>meixa']

list(map(<span class="hljs-keyword">lambda</span> x: str_view(x, <span class="hljs-string">"a$"</span>), txt5))

# ['maç<a>', 'banan<a>', 'ameix<a>']

Conforme a documentação da biblioteca re, existem diversos caracteres especiais úteis para encontrar padrões:

# Para encontrar números, usamos:
str_view("Python é 10!", "\d")

# 'Python é <1><0>!'

str_view("Python é 10!", "\w") # alfanuméricos

# '<P><y><t><h><o><n> <é> <1><0>!'

str_view("Python é 10!", "\s") # espaços

# 'Python< >é< >10!'

str_view("Python é 10!", "[^\w\s]") # pontuações: [^] significa qualquer caracter exceto a regex em seguida

# 'Python é 10<!>'

Aplicando regex

Agora que você aprendeu o básico de expressões regulares, vamos explorar algumas funções úteis que a biblioteca pandas oferece para manipular strings. Em resumo:

  • pd.Series.str.contains() para verificar se um padrão é encontrado em uma string;
  • pd.Series.str.extract() para extrair um grupo de padrão encontrado de uma string;
  • pandas.Series.str.replace() para substituir um padrão encontrado em uma string.

Vamos aos exemplos (consulte a documentação para detalhes):

# pandas Series de exemplo
txt6 = pd.Series(["Python é 10!", "python é 10", "Pythoné10!"])
# Verificando se há números seguidos de uma pontuação no final da string
txt6.str.contains(pat = "[\d]!$")
# 0 True
# 1 False
# 2 True
# dtype: bool
# Extraindo letras maiúsculas do início da string
txt6.str.extract(pat = "(^[A-Z])", expand = False)
# 0 P
# 1 NaN
# 2 P
# dtype: object
# Substituindo espaços por quebras de linha na string
txt6.str.replace(pat = "\s", repl = "\n", regex = True)
# 0 Python\né\n10!
# 1 python\né\n10
# 2 Pythoné10!
# dtype: object

Tenha acesso ao código e suporte desse e de mais 500 exercícios no Clube AM!

Quer o código desse e de mais de 500 exercícios de análise de dados com ideias validadas por nossos especialistas em problemas reais de análise de dados do seu dia a dia? Além de acesso a vídeos, materiais extras e todo o suporte necessário para você reproduzir esses exercícios? Então, fale com a gente no Whatsapp e veja como fazer parte do Clube AM, clicando aqui.

Compartilhe esse artigo

Facebook
Twitter
LinkedIn
WhatsApp
Telegram
Email
Print

Comente o que achou desse artigo

Outros artigos relacionados

Coletando dados regionais do CAGED no Python

Os dados regionais do CAGED permitem analisar o mercado de trabalho de forma detalhada, em termos de setores, educação, rendimento e características pessoais dos trabalhadores brasileiros. Neste exercício mostramos como acessar estas informações online via Python.

Coletando dados de Setores Censitários do Censo 2022 no Python

Dados sobre a demografia e o território são primordiais para definir e implementar políticas públicas, áreas de atuação comercial e/ou estratégias de marketing. Sendo assim, saber usar os dados do Censo 2022 pode trazer vantagens competitivas. Neste exercício mostramos como obter os dados da Malha de Setores Censitários no formato vetorial (GeoJson) usando o Python.

Boletim AM

Receba diretamente em seu e-mail gratuitamente nossas promoções especiais e conteúdos exclusivos sobre Análise de Dados!

Boletim AM

Receba diretamente em seu e-mail gratuitamente nossas promoções especiais e conteúdos exclusivos sobre Análise de Dados!

como podemos ajudar?

Preencha os seus dados abaixo e fale conosco no WhatsApp

Boletim AM

Preencha o formulário abaixo para receber nossos boletins semanais diretamente em seu e-mail.