<jupyter_start><jupyter_text>Strings - Python suporta strings como um tipo de dado básico.- Stings são objetos imutáveis. Não podem ser alteradas após sua criação.Quando um método que altera uma string é chamado; na verdade este retorna uma nova string.  Strings formatadas  Tipos de ApresentaçãoVocê viu a formatação básica de strings com f-strings. Quando você especifica um espaço reservado para um valor em uma f-string, Python assume que o valor deve ser exibido como uma string, a menos que você especifique outro tipo. Em alguns casos, o tipo é obrigatório. Por exemplo, vamos formatar o valor de ponto flutuante 17.489 arredondado para a posição dois centésimos:<jupyter_code>f'{17.489:.2f}'<jupyter_output><empty_output><jupyter_text>Python oferece suporte a precisão apenas para valores de ponto flutuante e **Decimal**. - A formatação é dependente do tipo - se você tentar usar **.2f** para formatar uma string como **'hello'**, ocorre um **ValueError**.     - O tipo de apresentação **f** no especificador de formato **.2f** é necessário.     - Indica que tipo que está sendo formatado para que o Python possa determinar se as outras informações de formatação são permitidas para esse tipo. - A lista completa com dos tipos pode ser acessada em: https://docs.python.org/3/library/string.htmlformatspec  InteirosO tipo de apresentação **d** formata valores inteiros como strings<jupyter_code>f'{10:d}'<jupyter_output><empty_output><jupyter_text>Caracteres O tipo de apresentação **c** formata um código de caractere inteiro como o caractere correspondente<jupyter_code>f'{65:c} {97:c}'<jupyter_output><empty_output><jupyter_text>O tipo de apresentação **s** é o padrão. - Se você especificar **s** explicitamente, o valor a formatar deve ser uma variável que faz referência a uma string,- uma expressão que produz uma string - ou um literal de string, como em f'{"hello":s}. - Se você não especificar um tipo de apresentação, como em {7}, os valores não string, como o inteiro 7, são convertidos em strings:<jupyter_code>f'{"hello":s} {7}'<jupyter_output><empty_output><jupyter_text>Valores de ponto flutuante e DecimalVocê usou o tipo de apresentação **f** para formatar valores de ponto flutuante e decimais. - Para valores extremamente grandes, ou pequenos, a notação exponencial (científica) pode ser usada para formatar os valores com o tipo de apresentação **e** ou (**E**).<jupyter_code>from decimal import Decimal
f'{Decimal("10000000000000000000000000.0"):.3f}'
f'{Decimal("10000000000000000000000000.0"):.3e}'<jupyter_output><empty_output><jupyter_text>** Larguras e alinhamento de campoPor padrão, o Python alinha os números à direita e à esquerda outros valores, como strings- Os resultados abaixo estão entre colchetes ([]) para que você possa ver como os valores se alinham no campo:<jupyter_code>f'[{27:10d}]'
f'[{3.5:10f}]'
f'[{"hello":10}]'<jupyter_output><empty_output><jupyter_text>Por padrão, Python formata valores flutuantes com seis dígitos de precisão para à direita do ponto decimal.- Para valores com menos caracteres do que o campo largura, as posições restantes dos caracteres são preenchidas com espaços. - Valores com mais caracteres do que a largura do campo, use quantas posições de caracteres forem necessárias.  Especificando explicitamente o alinhamento à esquerda e à direita em um campoLembre-se de que você pode especificar o alinhamento à esquerda e à direita com ****:<jupyter_code>f'[{27:<15d}]'
f'[{3.5:<15f}]'
f'[{"hello":>15}]'<jupyter_output><empty_output><jupyter_text>Centralizando um valor em um campoAlém disso, você pode centralizar valores:<jupyter_code>f'[{27:^7d}]'
f'[{3.5:^7.1f}]'
f'[{"hello":^7}]'<jupyter_output><empty_output><jupyter_text>**Exercício 01** Exiba em linhas separadas o seu nome à direita, ao centro e alinhado à esquerda em um campo de 10 caracteres. Coloque cada resultado entre colchetes para que você possa ver oo alinhamento resulta mais claramente.<jupyter_code>print(f'Alinhado à direita \t:\t [{"Matheus":>10}]')
print(f'Alinhado à esquerda \t:\t [{"Matheus":<10}]')
print(f'Alinhado ao centro \t:\t [{"Matheus":^10}]')<jupyter_output>Alinhado à direita 	:	 [   Matheus]
Alinhado à esquerda 	:	 [Matheus   ]
Alinhado ao centro 	:	 [ Matheus  ]<jupyter_text>Formatação NuméricaExistem vários recursos de formatação numérica. - Por exemplo, àss vezes é desejável forçar o sinal em um número positivo<jupyter_code>f'[{27:+10d}]'<jupyter_output><empty_output><jupyter_text>O + antes da largura do campo especifica que um número positivo deve ser precedido por um **+**. Um número negativo sempre começa com um **-**. - Para preencher os caracteres restantes do campo com **0**s em vez de espaços, coloque um 0 antes da largura do campo (e depois do + se houver):<jupyter_code>f'[{27:+010d}]'<jupyter_output><empty_output><jupyter_text>Usando um espaço onde um sinal + apareceria Um espaço indica que os números positivos devem mostrar um caractere de espaço na posição do sinal.- Isso é útil para alinhar valores positivos e negativos para fins de exibição:<jupyter_code>print(f'{27:d}\n{27: d}\n{-27: d}')<jupyter_output>27
 27
-27<jupyter_text>Agrupando dígitosVocê pode formatar números com separadores de milhares usando uma vírgula (,), da seguinte maneira:<jupyter_code>f'{12345678:,d}'
f'{123456.78:,.2f}'<jupyter_output><empty_output><jupyter_text>O Método de string *format*As f-strings do Python foram adicionadas à linguagem na versão 3.6. - Antes disso, a formatação era feita usando o método __*format*__. - Mostramos o método de formatação aqui porque você encontrará em código escrito antes do Python 3.6.     - Você verá frequentemente o método de formatação no Python documentação e em muitos livros e artigos Python escritos antes que as f-strings fossem introduzidas. Você chama o formato do método em uma string de formato contendo espaços reservados com chaves ({}),possivelmente com especificadores de formato. Você passa para o método os valores a serem formatados. Vamosformate o valor flutuante 17.489 arredondado para a posição dos centésimos:<jupyter_code>'{:.2f}'.format(17.489)<jupyter_output><empty_output><jupyter_text>Em um espaço reservado, se houver um especificador de formato, você o precede por dois-pontos (:), como nas strings f.O resultado da chamada de formato é uma nova string contendo os resultados formatados.  Multiplos marcadoresUma string de formato pode conter vários marcadores de posição, caso em que o método do formatoos argumentos correspondem aos marcadores da esquerda para a direita:<jupyter_code>'{} {}'.format('Amanda', 'Cyan')<jupyter_output><empty_output><jupyter_text>Argumentos de referência por número de posiçãoA string de formato pode fazer referência a argumentos específicos por sua posição no formatolista de argumentos do método, começando com a posição 0:<jupyter_code>'{0} {0} {1}'.format('Happy', 'Birthday')<jupyter_output><empty_output><jupyter_text>Referenciando argumentos de palavras-chaveVocê pode fazer referência a argumentos de palavra-chave por suas chaves nos marcadores de posição:<jupyter_code>'{first} {last}'.format(first='Amanda', last='Gray')
'{last} {last}'.format(first='Amanda', last='Gray')<jupyter_output><empty_output><jupyter_text>Concatenando e repetindo stringsLembre-se que já usamos o operador **+** para concatenar strings e o operador **\*** pararepetir strings. Você também pode realizar essas operações com atribuições aumentadas. - Strings são imutáveis, então cada operação atribui um novo objeto de string à variável:<jupyter_code>s1 = 'happy'
s2 = 'birthday'
s1 += ' ' + s2
s1
symbol = '>'
symbol *= 5
symbol<jupyter_output><empty_output><jupyter_text>**Exercício 02** Use o operador **+=** para concatenar seu nome e sobrenome. Então use o operador **\*=** para criar uma barra de asteriscos com o mesmo número de caracteres que seu nome completo e exibir a barra acima e abaixo do seu nome.<jupyter_code>name = 'Matheus'
middle = 'Percário'
last = 'Bruder'

name += ' ' + middle
name += ' ' + last
ast = '*'
ast *= len(name)

print(f'{ast}\n{name}\n{ast}')<jupyter_output>***********************
<NAME>
***********************<jupyter_text>Métodos de string ![image.png](attachment:image.png)<jupyter_code>sentence = 'to be or not to be that is the question'<jupyter_output><empty_output><jupyter_text>O método de string **count** retorna o número de vezes que seu argumento ocorre na string emqual o método é chamado:<jupyter_code>sentence.count('to')<jupyter_output><empty_output><jupyter_text>![image.png](attachment:image.png)  Localizando uma substring em uma stringO método de string **index** procura uma substring dentro de uma string e retorna o primeiro índice em em que a substring é encontrada; caso contrário, ocorre um **ValueError**:<jupyter_code>sentence.index('be')<jupyter_output><empty_output><jupyter_text>O método de string **rindex** executa a mesma operação que **index**, mas pesquisa a partir do final da string e retorna o último índice no qual a substring foi encontrada; caso contrário, um ocorre um erro **ValueError**<jupyter_code>sentence.rindex('be')<jupyter_output><empty_output><jupyter_text>![image.png](attachment:image.png)  Removendo espaços em branco de strings    Existem vários métodos de string para remover espaços em branco das extremidades de uma string.    - Cada um retorna uma nova string deixando a original inalterada. > Strings são imutáveis, então cada método que parece modificar uma string retorna uma nova.  Removendo espaços em branco à esquerda e à direitaVamos usar o método de string **strip** para remover os espaços em branco à esquerda e à direita de uma string:- o método **lstrip** remove somente os espaços da esquerda.- o método **rstrip** remoce somente os espaços da direita.<jupyter_code>sentence = '\t \n This is a test string. \t\t \n'
print(sentence)
sentence.strip()
sentence<jupyter_output><empty_output><jupyter_text>![image.png](attachment:image.png)   Agrupar métodos  Alterando entre maiúsculas e mínusculasNos capítulos anteriores, você usou métodos de string inferior e superior para converter strings para todas as minúsculasou todas as letras maiúsculas. Você também pode alterar a capitalização de uma string com métodoscapitalize e título. **Quadrilha, <NAME>**João amava Teresa que amava Raimundoque amava Maria que amava Joaquim que amava Lilique não amava ninguém.João foi pra os Estados Unidos, Teresa para o convento,Raimundo morreu de desastre, Maria ficou para tia,Joaquim suicidou-se e Lili casou com <NAME>que não tinha entrado na história.  **Exercício 03** Considerando a **Quadrilha** como string de entrada. Escreva um programa para:- Contar quantas vezes aparece ‘amava’.- Encontrar o primeiro e o último índice em que aparece ‘amava’.- Encontrar todos os índices em que aparece ‘amava’.- Substituir ‘amava’ por ‘treinava’.- Indique quais linhas começam com ‘que’.<jupyter_code>quadrilha = """João amava Teresa que amava Raimundo
que amava Maria que amava Joaquim que amava Lili
que não amava ninguém.
João foi pra os Estados Unidos, Teresa para o convento,
Raimundo morreu de desastre, Maria ficou para tia,
Joaquim suicidou-se e Lili casou com <NAME>
que não tinha entrado na história."""
# Contar quantas vezes aparece ‘amava’.
print(f'quadrilha.count("amava") = {quadrilha.count("amava")}')
# Encontrar o primeiro e o último índice em que aparece ‘amava’.
print(f'Primeiro índice = {quadrilha.index("amava")}')
print(f'Último índice = {quadrilha.rindex("amava")}')
quadrilha.index("amava", 0, len(quadrilha))
len(quadrilha)
# Encontrar todos os índices em que aparece ‘amava’.
indices = []
idx = 0

while True:
    idx = quadrilha.index('amava', idx + 1)
    indices.append(idx)

    if idx == quadrilha.rindex('amava'):
        break
    
print(indices)
# Substituir ‘amava’ por ‘treinava’.
quadrilha = quadrilha.replace('amava', 'treinava')
# print(quadrilha)
# Indique quais linhas começam com ‘que’.
for idx, linha in enumerate(quadrilha.splitlines()):
    if linha[0] == 'q' and linha[1] == 'u' and linha[2] == 'e':
        # print(linha)
        print(f'Linha [{idx}] começa com "que"')<jupyter_output>Linha [1] começa com "que"
Linha [2] começa com "que"
Linha [6] começa com "que"<jupyter_text>Tokens- Quando lemos uma sentença, nosso cérebro quebra a sentença em palavras, ou tokens, cada qual com um significado.    - Este processo é chamado tokenização.- Interpretadores e compiladores realizam tokenização para quebrar as sentenças em palavras-chave, operadores, variaveis, etc.- Tokens são separados por delimitadores, tipicamente espaços em branco.    - espaço, tab, nova linha e retorno de carro.  **Exercício 04**Ainda considerando a **Quadrilha**, escreva scripts para:- Obter uma lista com todas a palavras do texto- Separar o texto onde exista ‘,’.- Substitua os espaços por ‘__’.- Obter uma lista onde conste cada palavra existente no texto, uma única vez, juntamente com sua frequência.<jupyter_code>quadrilha = """João amava Teresa que amava Raimundo
que amava Maria que amava Joaquim que amava Lili
que não amava ninguém.
João foi pra os Estados Unidos, Teresa para o convento,
Raimundo morreu de desastre, Maria ficou para tia,
Joaquim suicidou-se e Lili casou com <NAME>
que não tinha entrado na história."""
# Obter uma lista com todas a palavras do texto
palavras = quadrilha.split()
palavras
# Separar o texto onde exista ‘,’.
quadrilha.split(',')
# Substitua os espaços por ‘__’.
new_quadrilha = quadrilha.replace(" ", "__")
new_quadrilha
# Obter uma lista onde conste cada palavra existente no texto, uma única vez, juntamente com sua frequência.
frequencias = []
palavras_processadas = []
palavras = quadrilha.split()

# preprocessamento
for p in palavras:
    if p[-1] in ",.:;?!":
        palavras_processadas.append(p[:-1])
    else:
        palavras_processadas.append(p)

# Determinando frequencias
for palavra in palavras_processadas:
    freq = palavras_processadas.count(palavra)
    t = (palavra, freq)
    if t not in frequencias:
        frequencias.append(t)

# Printando resultado
for p, f in frequencias:
    print(f'{p:^14} -> {f}')<jupyter_output>João      -> 2
    amava      -> 6
    Teresa     -> 2
     que       -> 6
   Raimundo    -> 2
    Maria      -> 2
   Joaquim     -> 2
     Lili      -> 2
     não       -> 2
   ninguém     -> 1
     foi       -> 1
     pra       -> 1
      os       -> 1
   Estados     -> 1
    Unidos     -> 1
     para      -> 2
      o        -> 1
   convento    -> 1
    morreu     -> 1
      de       -> 1
   desastre    -> 1
    ficou      -> 1
     tia       -> 1
 suicidou-se   -> 1
      e        -> 1
    casou      -> 1
     com       -> 1
      J        -> 1
    Pinto      -> 1
  Fernandes    -> 1
    tinha      -> 1
   entrado     -> 1
      na       -> 1
   história    -> 1<jupyter_text>Expressões regulares Uma expressão regular é um padrão de texto usado para encontrar strings que combinam com este padrão.O módulo **re**, fornece meios para o processamento de expressões regulares em Pythonhttps://docs.python.org/3/library/re.html - As expressões regulares podem ajudá-lo a extrair dados de texto não estruturado, como publicações em mídias sociais. - Elas também são importantes para garantir que os dados estejam no formato correto antes você tenta processar Validando DadosAntes de trabalhar com dados de texto, você costuma usar expressões regulares para validar os dados. Por exemplo, você pode verificar se:• Um CEP dos EUA consiste em cinco dígitos (como 02215) ou cinco dígitos seguidos porum hífen e mais quatro dígitos (como 02215-4775).• Um sobrenome de string contém apenas letras, espaços, apóstrofos e hifens.• Um endereço de e-mail contém apenas os caracteres permitidos na ordem permitida.• O número do Seguro Social dos EUA contém três dígitos, um hífen, dois dígitos, umhífen e quatro dígitos, e segue outras regras sobre os números específicos quepode ser usado em cada grupo de dígitos.Raramente você precisará criar suas próprias expressões regulares para itens comuns como esses.Sites como- https://regex101.com- http://www.regexlib.com- https://www.regular-expressions.infoe outros oferecem repositórios de expressões regulares existentes que você pode copiar e usar.Muitos sites como esses também fornecem interfaces nas quais você pode testar expressões regulares paradeterminar se eles atenderão às suas necessidades  Outros usos de expressões regularesAlém de validar dados, as expressões regulares costumam ser usadas para:- Extrair dados do texto (às vezes conhecido como raspagem) - por exemplo, localizar todos URLs em uma página da web. [Você pode preferir ferramentas como BeautifulSoup, XPath e lxml.]- Limpar dados - Por exemplo, removendo dados desnecessários, removendo dados duplicados, tratar dados incompletos, correção de erros de digitação, garantia de formatos de dados consistentes, lidar com outliers e muito mais.- Transforme os dados em outros formatos - por exemplo, reformatando os dados que foram coletados como valores separados por tabulação ou por espaço em valores separados por vírgula (CSV) para um aplicativo que exige que os dados estejam no formato CSV.  O módulo _re_ e a função _fullmatch_Para usar expressões regulares, importe o módulo re da biblioteca padrão do Python:<jupyter_code>import re<jupyter_output><empty_output><jupyter_text>Uma das funções de expressão regular mais simples é a função **fullmatch**, que verifica se ostring inteira em seu segundo argumento corresponde ao padrão em seu primeiro argumento.<jupyter_code>pattern = '02215'
'Match' if re.fullmatch(pattern, '02215') else 'No match'
'Match' if re.fullmatch(pattern, '51220') else 'No match'<jupyter_output><empty_output><jupyter_text>Classes de caracteres e sequências especiaisUma classe de caracteres especifica um grupo de caracteres em uma string.- Os metacaracteres ‘[’ e ‘]’ denotam uma **classe de expressões regulares**.     - Exemplo, a expressão regular "[abc]" identifica as letras a, b, c.- Pode-se usar o caractere ‘-’ para indicar intervalos de caracteres.    - Ex. "[a-d]" é idêntico à "[abcd]".<jupyter_code>'Valid' if re.fullmatch('[A-Z][a-z]', 'Ae') else 'Invalid'<jupyter_output><empty_output><jupyter_text>- O metacaractere ‘^’ quando colocado junto a uma classe, este indica a negação da classe.      - Ex. “[^a-c]” – todo caractere exceto os caracteres a,b,c<jupyter_code>'Match' if re.fullmatch('[^a-z]', 'A') else 'No match'
'Match' if re.fullmatch('[^a-z]', 'a') else 'No match'<jupyter_output><empty_output><jupyter_text>- O caractere ‘|’ pode ser visto como ‘ou’.- Usado para testar a combinação de uma dentre as possíveis  expressões.    - Ex. com|org|edu- Adicinando ‘r’ antes da expressão regular, diz ao interpretador para considerar o ‘\’ como um caractere. - Assim r"\n" significa dois caracteres, o ‘\’ e o ‘n’. Classes de caracteres combinam, exatamente, com um caractere.- Metacaracteres de repetição (quantificadores) são usados para especificar o número de repetições que se deseja.**?** combina zero ou uma ocorrências da expressão que o precede. **+** combina uma ou mais ocorrências da expressão que o precede.  **\*** combina zero ou mais ocorrências da expressão que a precede. **{ n }** combina exatamente **n** ocorrências da expressão que o precede. **{m,n}** combina **entre m e n** ocorrências da expressão que o precede.   Os quantificadores * e +<jupyter_code>'Valid' if re.fullmatch('[A-Z][a-z]+', 'Wally') else 'Invalid'
'Valid' if re.fullmatch('[A-Z][a-z]*', 'Wally') else 'Invalid'
'Valid' if re.fullmatch('[A-Z][a-z]+', 'E') else 'Invalid'

# Invalid, pois 'E' precisa fazer parte das duas classes e não apenas uma.
'Valid' if re.fullmatch('[A-Z][a-z]*', 'E') else 'Invalid'
'Valid' if re.fullmatch('E{1}', 'E') else 'Invalid'<jupyter_output><empty_output><jupyter_text>A expressão regular **labell?ed** corresponde à **labelled** (grafia do inglês britânico) e **labeled** (a grafia do inglês americano), mas não a palavra incorreta **labellled**. - Em cada trecho abaixo, os primeiros cinco caracteres literais na expressão regular (**label**) correspondem ao primeiro cinco caracteres dos segundos argumentos. Então **l?** indica que pode haver **zero ou um caractere l** antes dos caracteres **ed** restantes.<jupyter_code>'Match' if re.fullmatch('labell?ed', 'labelled') else 'No match'
'Match' if re.fullmatch('labell?ed', 'labeled') else 'No match'
'Match' if re.fullmatch('labell?ed', 'labellled') else 'No match'<jupyter_output><empty_output><jupyter_text>![image.png](attachment:image.png)<jupyter_code>'Valid' if re.fullmatch(r'\d{5}', '02215') else 'Invalid'
'Valid' if re.fullmatch(r'\d{5}', '9876') else 'Invalid'<jupyter_output><empty_output><jupyter_text>Você pode combinar **pelo menos n ocorrências** de uma subexpressão com o quantificador **{n,}**. A seguinte expressão regular corresponde a strings contendo pelo menos três dígitos:<jupyter_code>'Match' if re.fullmatch(r'\d{3,}', '123') else 'No match'
'Match' if re.fullmatch(r'\d{3,}', '123456789') else 'No match'<jupyter_output><empty_output><jupyter_text>**Exercício 05** Crie e teste uma expressão regular que corresponda a um endereço de rua que consiste uma ou duas palavras, de um ou mais caracteres e um número com um ou mais dígitos. Os tokens devem ser separados por um espaço, como em **Paschoal Marmo 1888**.<jupyter_code>import re 

endereço = 'Paschoal Marmo 1888'
endereço = endereço.split()
#print(endereço)

flag = 0
# validando endereço
for e in endereço:
    if re.fullmatch('[A-Z][a-z]+', e) or re.fullmatch('[0-9]+', e):
        flag += 1

# testando validação
if flag == len(endereço):
    for e in endereço:
        print(f'{e}', end=' ')
    print(f'é um endereço válido.')<jupyter_output>['Paschoal', 'Marmo', '1888']
Paschoal Marmo 1888 é um endereço válido.<jupyter_text>Substituindo substringsO módulo **_re_** fornece a função **sub** para substituir padrões em uma string com base em padrões. Por padrão, a função **sub** substitui todas as ocorrências de um padrão com otexto de substituição que você especificar. Vamos converter uma string delimitada por tabulação em delimitada por vírgulas:<jupyter_code>re.sub(r'\t', ', ', '1\t2\t3\t4')<jupyter_output><empty_output><jupyter_text>A função **sub** recebe três argumentos obrigatórios:- o padrão para combinar (o caractere de tabulação '\t')- o texto de substituição (',') e- a string a ser pesquisada ('1\t2\t3\t4') A palavra-chave **_count_** pode ser usada para especificar o máximonúmero de substituições:<jupyter_code>re.sub(r'\t', ', ', '1\t2\t3\t4', count=2)<jupyter_output><empty_output><jupyter_text>Dividindo strings A função **split** divide um string em **_tokens_**, usando uma expressão regular para especificar o delimitador, e retorna uma lista de strings.Considere dividir uma string em tokens dividindo-a onde ocorrer **uma vírgula seguida de zero ou mais espaços em branco**- **\s** é a classe de caractere de espaço em branco e **\*** indica zero ou mais ocorrências da subexpressão anterior:<jupyter_code>re.split(r',\s*', '1, 2, 3,4, 5,6,7,8')<jupyter_output><empty_output><jupyter_text>Use o argumento de palavra-chave **maxsplit** para especificar o número máximo de divisões:<jupyter_code>re.split(r',\s*', '1, 2, 3,4, 5,6,7,8', maxsplit=2)<jupyter_output><empty_output><jupyter_text>**Exercício 06** Substitua cada ocorrência de um ou mais (+) caracteres de tabulação adjacentes na a seguinte string por uma vírgula e um espaço:**'A\tB\t\tC\t\t\tD'**<jupyter_code>import re

re.sub(r'\t+', ', ', 'A\tB\t\tC\t\t\tD')<jupyter_output><empty_output><jupyter_text>**Exercício 07** Use uma expressão regular e a função **split** para dividir a seguinte string eliminando o caracteres **$**.<jupyter_code>import re

re.split(r'\$+', 'Matheu&$$E$a nicolli vao$$$$passear no bosqu3$ hoj$e.')<jupyter_output><empty_output><jupyter_text>Outras funções de pesquisaAnteriormente, usamos a função **fullmatch** para determinar se uma string inteira correspondia a um expressão regular. - Existem várias outras funções de pesquisa. Aqui, discutimos o funções de pesquisa, **search**, **match**, **findall** e **finditer**  A função search- Encontra a primeira substring correspondente em qualquer lugar em uma string.- Retorna um objeto **match** (do tipo **SRE_Match**) que contém a substring correspondente.    - O método **group** do objeto **match** retorna a substring:<jupyter_code>result = re.search('Python', 'Python é legal')
result.group() if result else 'not found'<jupyter_output><empty_output><jupyter_text>Você pode pesquisar uma correspondência apenas no início de uma string com a função **match**.<jupyter_code>testStrings = [ "2x+5y","7y-3z" ]
expressions = [ "2x\+5y|7y-3z","[0-9][a-zA-Z0-9_].[0-9][yz]","\d\w-\d\w" ]<jupyter_output><empty_output><jupyter_text>O operador **.** combina com qualquer caractere.<jupyter_code>for expression in expressions:
    for testString in testStrings:
        if re.match( expression, testString ):
            print(expression, "matches", testString)<jupyter_output>2x\+5y|7y-3z matches 2x+5y
2x\+5y|7y-3z matches 7y-3z
[0-9][a-zA-Z0-9_].[0-9][yz] matches 2x+5y
[0-9][a-zA-Z0-9_].[0-9][yz] matches 7y-3z
\d\w-\d\w matches 7y-3z<jupyter_text>Muitas funções do módulo de referência recebem um argumento opcional de palavra-chave **flags** que muda como expressões regulares são combinadas. - Por exemplo, as correspondências diferenciam maiúsculas de minúsculas por padrão, mas pode-se usar a constante **IGNORECASE** do módulo **re**, para realizar uma pesquisa que não diferencia maiúsculas de minúsculas:<jupyter_code>result3 = re.search('Sam', 'SAM WHITE', flags=re.IGNORECASE)
result3.group() if result3 else 'not found'
result3.group()<jupyter_output><empty_output><jupyter_text>- O metacaractere ‘^’ indica que a expressão que o sucede deve aparecer no início da string;    - “^OLA” – combina com strings que começam com OLA.- O metacaractere ‘\$’ indica que a expressão que o precede deve aparecer no final da string;     - Ex. “AVA\$” – combina com strings que terminam com AVA.<jupyter_code>result = re.search('^Python', 'Python is fun')
result.group() if result else 'not found'
result = re.search('^fun', 'Python is fun')
result = re.search('Python$', 'Python is fun')
result.group() if result else 'not found'
result = re.search('fun$', 'Python is fun')
result.group() if result else 'not found'<jupyter_output><empty_output><jupyter_text>Encontrar todas as correspondências em uma stringA função **findall** encontra todos as substring correspondentes em uma string e retorna uma lista das substrings. Vamos extrair todos os números de telefone de uma string. Para simplificar, vamossupor que os números de telefone tenham o formato -:<jupyter_code>contact = '<NAME>, Home: 55555-1234, Work: 55555-4321'
re.findall(r'\d{5}-\d{4}', contact)<jupyter_output><empty_output><jupyter_text>A função **finditer** funciona como **findall**, no entanto retorna um iterável dos objetos correspondentes. - Para um grande número de correspondências, **finditer** pode economizar memória porque retorna uma correspondência por vez    - enquanto **findall** retorna todas as correspondências de uma vez<jupyter_code>for phone in re.finditer(r'\d{5}-\d{4}', contact):
    print(phone.group())<jupyter_output>55555-1234
55555-4321<jupyter_text>Você pode usar os metacaracteres parênteses - **( )** - para capturar substrings de uma correspondência. - Por exemplo, vamos capturar como substrings separadas o nome e o endereço de e-mail no texto da string:<jupyter_code>text = '<NAME>, e-mail: <EMAIL>'
pattern = r'([A-Z][a-z]+ [A-Z][a-z]+), e-mail: (\w+@\w+\.\w{3})'<jupyter_output><empty_output><jupyter_text>Vamos considerar a expressão regular:- **'([A-Z][a-z]+ [A-Z][a-z]+)'** corresponde a duas palavras separadas por um espaço.    -Cada palavra deve ter a letra inicial maiúscula.- **', e-mail:'** contém caracteres literais que correspondem a eles próprios.- **(\w+@\w+\.\w{3})** corresponde a um endereço de e-mail simples consistindo em um ou mais caracteres alfanuméricos (\w+), o caractere @, um ou mais caracteres alfanuméricos (\w+), um ponto (\.) e três caracteres alfanuméricos (\w{3}).     - O ponto deve ser precedido de \ pois é um metacaractere de expressão regular que corresponde um caractere.<jupyter_code>result = re.search(pattern, text)<jupyter_output><empty_output><jupyter_text>O método **groups** do objeto **match** reorna uma tupla das substrings capturadas:<jupyter_code>result.groups()<jupyter_output><empty_output><jupyter_text>O método **group** do objeto **match** retorna a correspondência inteira como uma única string:<jupyter_code>result.group()<jupyter_output><empty_output><jupyter_text>Você pode acessar cada substring capturada passando um número inteiro para o método **group**. - As substrings capturados são numerados a partir de 1 (ao contrário dos índices de lista, que começam em 0)<jupyter_code>result.group(1)
result.group(2)<jupyter_output><empty_output><jupyter_text>**Exercício 08** Crie uma expressão regular para obter o nome, o telefone e o email da senteça: <NAME>, phone: 123-4567, e-mail: <EMAIL><jupyter_code>text = '<NAME>, phone: 123-4567, e-mail: <EMAIL>'
pattern = r'([A-Z][a-z]+ [A-Z][a-z]+), phone: (\d{3}-\d{4}), e-mail: (\w+@\w+\.\w{3})'

result = re.search(pattern, text)
result.groups()
result.group()<jupyter_output><empty_output><jupyter_text>Introdução à ciência de dados: pandas, expressões regulares e pré-processamento de dados Os dados nem sempre vêm em formulários prontos para análise. - Podem, por exemplo, estar no formato errado, incorreto ou mesmo ausente. - Cientistas de dados podem gastar até 75% de seu tempo preparando dados antes de começarem seus estudos.O pré-processamento de dados também é chamado de *data munging* ou *data wrangling*. Duas das etapas mais importantes na manipulação de dados são a limpeza e transformação de dadosdados nos formatos ideais para seus sistemas de banco de dados e software analítico. Exemplos de limpeza de dados são:    - excluir observações com valores ausentes,- substituir valores razoáveis ​​por valores ausentes,- excluir observações com valores ruins,- substituir valores razoáveis ​​por valores ruins,- lançando outliers (embora às vezes você queira mantê-los),- eliminação de duplicatas (embora às vezes as duplicatas sejam válidas),- lidar com dados inconsistentes,- e mais. Você provavelmente já está pensando que a limpeza de dados é um processo difícil e confuso, onde você poderia facilmente tomar decisões erradas que afetariam negativamente seus resultados. - Você está correto!Quando você chegar aos estudos de caso de ciência de dados nos capítulos posteriores, verá esses dados ciência é mais uma ciência empírica, como a medicina, e menos uma ciência teórica, como física Teórica. As ciências empíricas baseiam suas conclusões em observações e experiências. Por exemplo, muitos medicamentos que efetivamente resolvem problemas médicos hoje foramdesenvolvido pela observação dos efeitos que as primeiras versões desses medicamentos tiveram em animais de laboratório e eventualmente humanos, e gradualmente refinando ingredientes e dosagens. Os dados de açõesos cientistas tomam pode variar por projeto, com base na qualidade e natureza dos dados e serafetados pela organização em evolução e padrões profissionais.Algumas transformações de dados comuns incluem:]• remover dados e recursos desnecessários (falaremos mais sobre os recursos nos dadosestudos de caso de ciências),• combinando recursos relacionados,• dados de amostragem para obter um subconjunto representativo (veremos no caso da ciência de dadosestudos que a amostragem aleatória é particularmente eficaz para isso e diremos por quê),• padronizar formatos de dados,• agrupamento de dados,• e mais.É sempre bom manter seus dados originais. Mostraremos exemplos simples de limpezae transformação de dados usando **Pandas Series** e **DataFrames**.  Limpando seus dadosValores de dados inválidos e valores ausentes podem afetar significativamente a análise de dados. Alguns cientistas de dados aconselham contra quaisquer tentativas de inserir "valores razoáveis". Em vez disso, eles defendem marcando claramente os dados ausentes e deixando para o pacote de análise de dados lidar com o questão. Vamos considerar um hospital que registra as temperaturas dos pacientes (e provavelmente outrossinais) quatro vezes por dia. Suponha que os dados consistam em um nome e quatro valores reais,tal como: ['Brown, Sue', 98.6, 98.4, 98.7, 0.0] Note que a última temperatura esta faltando e foi registrada como 0,0, talvez devido ao mau funcionamento do sensor.A média dos três primeiros valores é 98,57, o que está próximo do normal. Contudo,se você calcular a temperatura média incluindo o valor ausente para o qual 0,0 foisubstituído, a média é de apenas 73,93, resultado claramente questionável. Certamente, os médicos iriam não quero tomar medidas corretivas drásticas neste paciente - é crucial "obter os dados corretos".Uma maneira comum de limpar os dados é substituir um valor razoável pelo ausentetemperatura, como a média das outras leituras do paciente. Se tivéssemos feito isso acima,então a temperatura média do paciente permaneceria 98,57 - uma média muito mais prováveltemperatura, com base nas outras leituras.  Validação de dadosVamos começar criando uma **Serie** de códigos postais de cinco dígitos a partir de um dicionário de nome da cidade / codigo de 5 dígitos- Inserimos intencionalmente um CEP inválido para Miami:<jupyter_code>import pandas as pd
zips = pd.Series({'Boston': '02215', 'Miami': '3310'})
zips<jupyter_output><empty_output><jupyter_text>Embora *zips* pareça uma matriz bidimensional, na verdade é unidimensional. - A segundo coluna ”representa os valores do CEP da série (dos valores do dicionário), e a - “primeira coluna” representa seus índices (das chaves do dicionário).Podemos usar expressões regulares com **Pandas** para validar dados. - O atributo **str** de uma **Serie** fornece processamento de strings e vários métodos de expressão regular. - Vamos usar o método **match** do atributo **str** para verificar se cada CEP é válido:<jupyter_code>zips.str.match(r'\d{5}')<jupyter_output><empty_output><jupyter_text>O método **match** aplica a expressão regular **\d{5}** a _cada_ elemento da série, verificando se o elemento é composto de exatamente cinco dígitos. - Você não precisa fazer um laço explicitamente em todos os códigos postais.- Este é outro exemplo de estilo de programação com iteração interna em vez de externa. O método retorna uma nova **Serie** contendo **True** para cada elemento válido. Nesse caso, o CEP de Miami não corresponde, então seu elemento é **False**. Existem várias maneiras de lidar com dados inválidos. Uma é pegá-lo em sua fonte einteragir com a fonte para corrigir o valor. Isso nem sempre é possível. Por exemplo, oos dados podem estar vindo de sensores de alta velocidade na Internet das Coisas. Nesse caso, nós não seria capaz de corrigi-lo na fonte, portanto, poderíamos aplicar técnicas de limpeza de dados.No caso do CEP de Miami inválido de 3310, podemos procurar por CEPs de Miamicomeçando com 3310. Existem dois - 33101 e 33109 - e poderíamos escolher um deles.Às vezes, em vez de combinar um valor inteiro com um padrão, você vai querer saberse um valor contém uma substring que corresponda ao padrão. Neste caso, use o métodocontém em vez de correspondência. Vamos criar uma série de strings, cada uma contendo uma cidade dos EUA,estado e CEP, em seguida, determine se cada string contém uma substring que corresponde aopadrão **'[A-Z]{2}'** (um espaço, seguido por duas letras maiúsculas, seguidas por um espaço):<jupyter_code>cities = pd.Series(['Boston, MA 02215', 'Miami, FL 33101'])
cities<jupyter_output><empty_output><jupyter_text>Não especificamos os valores do índice, portanto, a Serie usa índices iniciado em zero por padrão. - O trecho a seguir usa **contains** para mostrar que ambos os elementos da série contêm substrings que correspondem a **'[A-Z]{2}'**. - Depois, **match** é usado para mostrar que nenhum valor do elemento corresponde a esse padrão em sua totalidade, porque cada um possui outros caracteres em seu valor completo.<jupyter_code>cities.str.contains(r' [A-Z]{2} ')
cities.str.match(r' [A-Z]{2} ')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09865718145972924, 'fraction_numerical': 0.01483442247773458, 'mean_word_length': 5.141913632514818, 'pattern_counts': {'":': 9, '<': 240, '<?xml version=': 0, '>': 276, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '58', 'dir': 'jupyter-structured-clean-dedup', 'id': '147464', 'license': 'MIT', 'n_tokens_mistral': 12897, 'n_tokens_neox': 12575, 'n_words': 4405, 'path': 'Aula06-strings/strings.ipynb', 'repo_name': 'matheuspercario/TT007-IntroducaoDatascience', 'size': '36401'}