Ao longo dos primeiros capítulos desse livro nós usamos strings para representar palavras ou frases que desejávamos imprimir. Nossa definição foi simples. Um string é simplesmente um grupo de caracteres entre aspas. Nesse capítulo vamos explorar strings com muito mais detalhes.
Até aqui vimos tipos de dados nativos como: int, float, bool, str e vimos também listas. Os tipos int, float e bool são considerados tipos simples ou primitivos pois seus valores não são compostos por outras partes menores. Eles não podem ser quebrados. Por outro lado, strings e listas são qualitativamente diferentes desses tipos pois eles são construídos de pedaços menores. No caso de strings, eles são construídos de strings menores, cada um contendo um caractere. Tipos que são compostos de pedaços menores são chamados tipos de dados compostos. Dependendo do que estamos fazendo, a gente pode querer tratar um tipo composto como uma entidade única (o todo), ou a gente pode querer acessar suas partes. Essa ambiguidade é útil. Strings podem ser definidos como coleções de sequencias de caracteres. Isto significa que assumimos que os caracteres individuais que compõem a cadeia estão em uma determinada ordem, da esquerda para a direita. Uma cadeia que não possui nenhum caractere, muitas vezes chamada de string vazio, é também considerado um string. É simplesmente uma sequência com zero caracteres e é representado por ‘’ ou “” (dois apóstrofes ou aspas sem nada entre eles – observe que o string com um ou mais caracteres em branco como ‘ ‘ é diferente do string vazio ‘’).
Em geral, você não pode executar operações matemáticas com strings, mesmo que os strings se pareçam com números. As seguintes operações são ilegais (assumindo que `` message`` seja um string): message - 1 "Hello" / 123 message * "Hello" "15" + 2 Curiosamente, o operador + funciona com strings. No entanto, esse o operador + representa concatenação e não adição. Concatenação significa juntar os dois operandos unindo o fim de um com o começo do outro. Por exemplo: fruta = " banana" tipo = "bolo de" print(tipo + fruta) A saída deste programa é bolo de banana. O espaço antes da palavra `` banana`` faz parte da cadeia, e é necessário para produzir o espaço entre os strings concatenados. Retire o espaço e execute o programa novamente. O operador * também funciona com strings; ele realiza repetição. Por exemplo, 'Vai'*3 é 'VaiVaiVai'. Um dos operadores tem que ser um string; o outro tem de ser um número inteiro. print("Vai "*6) nome = "Santos" print(nome * 3) print(nome + " Vai" * 3) print((nome + " Vai") * 3) Esta interpretação de + e * faz sentido por analogia com adição e multiplicação. Assim como 4*3 é equivalente a 4+4+4, nós esperamos que "Vai "*3 a ser o mesmo que "Vai "+"Vai "+" Vai ", e é. Note-se também no último exemplo, que a ordem de operações para * e + é o mesmo que foi para a aritmética. A repetição é feita antes da concatenação. Se você quer fazer com que a concatenação seja feita primeiro, você vai precisar usar parênteses. Teste seu entendimento
Q-3: O que é impresso pelos seguintes comandos? s = "python" t = "rocks" print(s+t)
Q-4: O que é impresso pelos seguintes comandos? s = "python" excl = "!" print(s+excl*3)
O operador de indexação (o Python usa colchetes para incluir o índice) seleciona um único caractere de um string. Os caracteres são acessados por sua posição ou valor do índice. Por exemplo, na sequência mostrada abaixo, os 14 caracteres são indexados da esquerda para a direita a partir posição 0 até a posição 13. As posições podem ser acessadas também da direita para a esquerda usando números negativos, onde -1 é o índice mais à direita e assim por diante. Note-se que o caractere no índice 6 (ou -8) é o caractere em branco. escola = "Carlos Gomes" m = escola[2] print(m) ultimo = escola[-1] print(ultimo) A expressão escola[2] seleciona o caractere no índice 2 de escola, e cria um novo string contendo apenas este caractere. A variável m faz referência ao resultado. Lembre-se que os cientistas da computação muitas vezes começam a contagem do zero. A letra no índice zero do "Carlos Gomes" é C. Então, na posição [2] temos a letra r. Se você quiser a letra de índice zero de um string, simplesmente coloque 0, ou qualquer expressão com o valor 0, dentro dos colchetes. Experimente. A expressão entre parênteses é chamada de índice. Um índice especifica um membro de uma coleção ordenada. Neste caso, a coleção de caracteres na sequência. o índice indica qual caractere você quer. Pode ser qualquer expressão inteira desde que ela seja avaliada como um valor de índice válido. Observe que a indexação retorna um string — o Python não tem nenhum tipo especial para um único caractere. É apenas uma sequência de comprimento 1. Teste seu entendimento
Q-6: O que é impresso pelos seguintes comandos? s = "python rocks" print(s[3])
Q-7: O que é impresso pelos seguintes comandos? s = "python rocks" print(s[2] + s[-5])
Nós já vimos que cada instância de tartaruga tem seus próprios atributos e um número de métodos que podem ser aplicados à instância. Por exemplo, nós escrevemos tess.right(90) para que o objeto tartaruga tess execute o método right para virar 90 graus para a direita. A “notação de ponto” é a forma de ligar o nome de um objeto com o nome de um método que ele pode executar. Strings também são objetos. Cada instância de string tem seus próprios atributos e métodos. O atributo mais importante do string é a coleção de caracteres. Há uma grande variedade de métodos. Rode o seguinte programa. ss = "Hello, World" print(ss.upper()) tt = ss.lower() print(tt) Neste exemplo, upper é um método que pode ser chamado em qualquer objeto string para criar um novo string no qual todos os caracteres estão em maiúsculas. lower funciona de forma semelhante, onde todos os caracteres do novo string estão em minúsculas. (O string original ss permanece inalterado. Um novo string é criado e é referenciado por tt.) Além de upper e lower, a tabela a seguir apresenta um resumo de alguns outros métodos úteis de string. Existem alguns exemplos em activecode que se seguem, de modo que você pode experimentá-los.
Você deve experimentar esses métodos para que você entenda o que eles fazem. Observe que os métodos que retornam um string não alteram o original. Você também pode consultar a documentação do Python para strings. ss = " Hello, World " els = ss.count("l") print(els) print("***"+ss.strip()+"***") print("***"+ss.lstrip()+"***") print("***"+ss.rstrip()+"***") news = ss.replace("o", "***") print(news) food = "banana bread" print(food.capitalize()) print("*"+food.center(25)+"*") print("*"+food.ljust(25)+"*") # estrelas foram incluidas para mostrar limites print("*" +food.rjust(25)+"*") print(food.find("e")) print(food.find("na")) print(food.find("b")) print(food.rfind("e")) print(food.rfind("na")) print(food.rfind("b")) print(food.index("e")) Teste seu entendimento
Q-11: O que é impresso pelos seguintes comandos? s = "python rocks" print(s.count("o") + s.count("p"))
Q-12: O que é impresso pelos seguintes comandos? s = "python rocks" print(s[1]*s.index("n"))
A função len, quando aplicada a um string, retorna o número de caracteres no string (ou seja, o seu comprimento). fruta = "Banana" print(len(fruta)) Para pegar o último caractere de um string, você pode ficar tentado a experimentar algo como: fruta = "Banana" sz = len(fruta) last = fruta[sz] # ERROR! print(last) Isso não vai funcionar. Isso causa o erro em tempo de execução IndexError: string index out of range. A razão é que não há nenhum caractere na posição de índice 6 em "Banana". Como começamos a contar do zero, os seis índices são numeradas de 0 a 5. Para pegar o último caractere, temos que subtrair 1 comprimento. Experimente, tente executar o exemplo acima. fruta = "Banana" sz = len(fruta) lastch = fruta[sz-1] print(lastch) Normalmente, um programador Python irá acessar o último caractere combinando as duas linhas de código acima. lastch = fruta[len(fruta)-1] Teste seu entendimento
Q-16: O que é impresso pelos seguintes comandos? s = "python rocks" print(len(s))
Q-17: O que é impresso pelos seguintes comandos? s = "python rocks" print(s[len(s)-5])
Um substring de um string é chamado de fatia (do inglês slice). Selecionar uma fatia é semelhante a selecionar um caractere: singers = "Peter, Paul, and Mary" print(singers[0:5]) print(singers[7:11]) print(singers[17:21]) O operador de fatia [n:m] retorna a parte do string a partir do n-ésimo caractere até o m-ésimo caractere, incluindo o primeiro mas excluindo o último. Em outras palavras, comece com o caractere no índice n e vá até, mas não inclua, o caractere no índice m. Esse comportamento pode parecer contra-intuitivo, mas se você se lembra a função range, ela não inclui o seu ponto final também. Se você omitir o primeiro índice (antes dos dois pontos), a fatia começa no início da cadeia. Se você omitir o segundo índice, a fatia vai até o fim da cadeia. fruta = "banana" print(fruta[:3]) print(fruta[3:]) O que você acha que fruta[:] significa? Teste seu entendimento
Q-20: O que é impresso pelos seguintes comandos? s = "python rocks" print(s[3:8])
Q-21: O que é impresso pelos seguintes comandos? s = "python rocks" print(s[7:11]*3) index:: comparação de strings
Os operadores de comparação também funcionam com strings. Para ver se dois strings são iguais, basta escrever uma expressão booleana usando o operador de igualdade. word = "banana" if word == "banana": print("Yes, we have bananas!") else: print("Yes, we have NO bananas!") Outras operações de comparação são úteis para colocar palavras em ordem lexicográfica <http://en.wikipedia.org/wiki/Lexicographic_order> __. Isto é semelhante à ordem alfabética usada em um dicionário, exceto que todas as letras maiúsculas vêm antes de todas as letras minúsculas. word = "zebra" if word < "banana": print("Your word, " + word + ", comes before banana.") elif word > "banana": print("Your word, " + word + ", comes after banana.") else: print("Yes, we have no bananas!") Deve ser evidente para você que a palavra apple seria inferior a (deve vir antes) palavra` banana`. Afinal, a vem antes de b no alfabeto. Mas e se considerarmos as palavras apple e Apple? Eles são iguais? print("apple" < "banana") print("apple" == "Apple") print("apple" < "Apple") Acontece que, como você deve se lembrar da nossa discussão sobre nomes de variáveis, que letras maiúsculas e minúsculas são consideradas diferentes umas das outras. A forma como o computador sabe que eles são diferentes é que cada caractere corresponde a um valor inteiro único. Por exemplo, “A” é de 65, “B” é de 66, e “5” é 53. Você pode descobrir o chamado valor ordinal de um caractere utilizando a função ord. print(ord("A")) print(ord("B")) print(ord("5")) print(ord("a")) print("apple" > "Apple") Quando você compara caracteres ou strings, o Python converte os caracteres para seus valores ordinais e compara os inteiros da esquerda para a direita. Como você pode ver no exemplo acima, “a” é maior que “A” de forma que “apple” é maior do que “Apple”. Nós geralmente ignoramos a capitalização ao comparar duas palavras. No entanto, os computadores não. Uma maneira comum de resolver este problema é converter as strings para um formato padrão, tal como todas as letras minúsculas, antes de realizar a comparação. Há também uma função semelhante chamada chr que converte inteiros para o seu caractere equivalente. print(chr(65)) print(chr(66)) print(chr(49)) print(chr(53)) print("O caractere correspondente a 32 e",chr(32),"!!!") print(ord(" ")) Uma coisa a notar nos dois últimos exemplos é o fato de que o caractere de espaço tem um valor ordinal (32). Mesmo que você não o veja, ele é um caractere real. Às vezes chamamos esses caracteres de não impressos. Teste seu entendimento
Q-27: Qual o resultado da seguinte comparação:
Q-28: Qual o resultado da seguinte comparação:
Q-29: Qual o resultado da seguinte comparação:
Uma última coisa que faz que strings sejam diferentes de alguns outros tipos coletivos de Python é que você não tem permissão para modificar os caracteres individuais na coleção. É tentador usar o operador [] no lado esquerdo de uma atribuição com a intenção de mudar um caractere em um string. Por exemplo, no código a seguir, gostaríamos de mudar a primeira letra de conversa. conversa = "Ola, mundo!" conversa[0] = 'B' # ERROR! print(conversa) Em vez de produzir a saída Bla, mundo, este código produz o erro de execução TypeError: 'str' object does not support item assignment. Strings são imutáveis, o que significa que você não pode mudar um string existente. O melhor que você pode fazer é criar um novo string que é uma variação do original. conversa = "Ola, mundo!" nova_conversa = 'B' + conversa[1:] print(nova_conversa) print(conversa) # mesmo que antes A solução aqui é concatenar uma nova primeira letra com uma fatia de conversa. Esta operação não tem efeito sobre o string original. Teste seu entendimento
Q-32: O que é impresso pelos seguintes comandos? s = "Ball" s[0] = "C" print(s)
Um grande número de computações envolvem o processamento de item de um conjunto de cada vez. Para strings, isto significa que nós gostaríamos de processar um caractere de cada vez. Muitas vezes, nós começamos no início, selecionamos um caractere de cada vez, fazemos alguma coisa com ele, e continuamos até o final. Este padrão de processamento é chamado um percurso. Anteriormente, vimos que o comando for pode iterar sobre os itens de uma sequência (uma lista de nomes no caso abaixo). for um_nome in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]: convite = "Oi " + um_nome + ". Venha para a festa nesse sabado!" print(convite) Lembre-se que a variável do laço assume cada valor da sequência de nomes. O corpo é executado uma vez para cada nome. O mesmo era verdade para a sequência de números inteiros criada pela função range. for um_valor in range(10): print(um_valor) Como um string é simplesmente uma sequência de caracteres, o laço for itera sobre cada caractere automaticamente. for um_char in "Venha para a festa": print(um_char) A variável um_char do laço recebe automaticamente cada caractere da sequência “Venha para a festa”. Vamos nos referir a esse tipo de iteração de sequência como iteração por item. Note que só é possível processar os caracteres um de cada vez, da esquerda para a direita. Teste seu entendimento
Q-36: Quantas vezes a palavra OLA é impressa pelos seguintes comandos? s = "viva o python" for ch in s: print("OLA")
Q-37: Quantas vezes a palavra OLA é impressa pelos seguintes comandos? s = "viva o python" for ch in s[3:8]: print("OLA")
Também é possível utilizar a função range para gerar sistematicamente os índices dos caracteres. O laço for pode então ser usado para iterar sobre essas posições. Estas posições podem ser utilizados em conjunto com o operador de indexação para acessar os caracteres individuais na sequência. Considere o seguinte exemplo no codelens. As posições de índice de “apple” são 0,1,2,3 e 4. Esta é exatamente a mesma sequência de números inteiros retornado por range(5). Na primeira vez dentro do laço for, idx será 0 e o “a” será impresso. Em seguida, idx receberá 1 e “p” será exibido. Isso vai se repetir para todos os valores do intervalo até, mas não incluindo, o 5. Como “e” tem índice 4, este programa vai mostrar todos os caracteres de “apple”. A fim de tornar a iteração mais genérica, podemos usar a função len para fornecer o limite para range. Este é um padrão muito comum para percorrer qualquer sequência por posição. Certifique-se de entender por que a função range se comporta corretamente ao usar len de um string como parâmetro. fruta = "apple" for idx in range(len(fruta)): print(fruta[idx]) Você também pode notar que a iteração por posição permite que o programador controle a direção da travessia, alterando a sequência de valores dos índices. Lembre-se que nós podemos criar tanto intervalos que contam para baixo quanto para cima. Assim o código a seguir irá imprimir os caracteres da direita para a esquerda. Simule os valores de idx e verifique que eles estão corretos. Em particular, note o início e o fim do intervalo. Teste seu entendimento
Q-41: Quantas vezes a letra o é impressa pelos seguintes comandos? s = "python rocks" for idx in range(len(s)): if idx % 2 == 0: print(s[idx])
O laço while também pode controlar a geração dos valores de índices. Lembre-se que o programador é responsável por configurar a condição inicial, certificando-se que a condição é correta e certificando-se de que algo muda dentro do corpo para garantir que a condição se tornará falsa. fruta = "apple" position = 0 while position < len(fruta): print(fruta[position]) position = position + 1 A condição do loop é position < len(fruta), por isso, quando position é igual ao comprimento do string, a condição é falsa, e o corpo do laço não é executado. O último caractere acessado é aquele com o índice len(fruta)-1, que é o último caractere no string. Aqui está o mesmo exemplo em codelens para que você possa verificar os valores das variáveis. Teste seu entendimento
Q-44: Quantas vezes a letra o é impressa pelos seguintes comandos? s = "python rocks" idx = 1 while idx < len(s): print(s[idx]) idx = idx + 2
O operador in testa se um string é um substring de outro: print('p' in 'apple') print('i' in 'apple') print('ap' in 'apple') print('pa' in 'apple') Note que um string é um substring de si mesmo, e o string vazio é um substring de qualquer outro string. (Note também que os cientistas da computação gostam de pensar sobre estes casos particulares com muito cuidado!) print('a' in 'a') print('apple' in 'apple') print('' in 'a') print('' in 'apple') O operador not in retorna o resultado lógico oposto de in. print('x' not in 'apple')
Combinando o operador in com concatenação de strings usando + e o padrão de acumulação, podemos escrever uma função que remove todas as vogais de um string. A idéia é começar com um string e iterar sobre cada caractere, verificando se o caractere é uma vogal. À medida que processamos os caracteres, vamos construindo uma nova cadeia contendo apenas os caracteres não vogais. Para fazer isso, usamos o padrão de acumulação. Lembre-se que o padrão de acumulação nos permite manter uma “total em execução”. Com strings, não estamos acumulando um total numérico. Em vez disso, estamos acumulando caracteres em um string. def removeVowels(s): vowels = "aeiouAEIOU" sWithoutVowels = "" for eachChar in s: if eachChar not in vowels: sWithoutVowels = sWithoutVowels + eachChar return sWithoutVowels print(removeVowels("compsci")) print(removeVowels("aAbEefIijOopUus")) A linha 5 usa o operador not in para verificar se o caractere atual não se encontra no string vowels. A alternativa para o uso deste operador seria escrever uma grande declaração if que verifica cada vogal individualmente. Note que precisaríamos usar operadores lógicos and para ter certeza de que o caractere não é uma vogal. if eachChar != 'a' and eachChar != 'e' and eachChar != 'i' and eachChar != 'o' and eachChar != 'u' and eachChar != 'A' and eachChar != 'E' and eachChar != 'I' and eachChar != 'O' and eachChar != 'U': sWithoutVowels = sWithoutVowels + eachChar Olhe atentamente para a linha 6 no programa acima (sWithoutVowels = sWithoutVowels + eachChar). Vamos fazer isso para cada caractere que não é uma vogal. Isso deve parecer muito familiar. Como descremos anteriormente, este é um exemplo do padrão de acumulação, desta vez usando um string para “acumular” o resultado final. Em palavras, ele diz que o novo valor de sWithoutVowels será o valor antigo de sWithoutVowels concatenado com o valor de eachChar. Estamos construindo o string resultante caractere por caractere. Dê uma olhada também na inicialização de sWithoutVowels. Começamos com um string vazio e, em seguida, adicionamos novos caracteres até o fim. Simule a execução da função usando codelens para ver a variável acumuladora crescer. Teste seu entendimento
Q-50: O que é impresso pelos seguintes comandos: s = "ball" r = "" for item in s: r = item.upper() + r print(r)
Esta seção descreve um exemplo muito mais interessante de iteração de strings e o padrão de acumulação. Mesmo que pareça que estamos fazendo algo que é muito mais complexo, o processamento básico é o mesmo que foi mostrado nas seções anteriores. Em 1968 Astrid Lindenmayer, uma bióloga, inventou um sistema formal que fornece uma descrição matemática do crescimento de plantas conhecido como um sistema-L. O sistema-L foi concebido para modelar o crescimento de sistemas biológicos. Você pode considerar que um sistema-L contem as instruções de como uma única célula pode se transformar em um organismo complexo. Sistemas-L podem ser utilizados para especificar as regras para todos os tipos de padrões interessantes. No nosso caso, vamos usá-los para especificar as regras para desenhar figuras. As regras de um sistema-L são na verdade um conjunto de instruções para transformar um string em um novo string. Depois de uma série de tais transformações de strings se completar, o string contém um conjunto de instruções. Nosso plano é deixar estas instruções dirigirem uma tartaruga para desenhar uma figura. Para começar, vamos ver um exemplo de conjunto de regras:
Cada conjunto de regras contém um axioma que representa o estado inicial do processo de transformação. As regras são da forma: lado esquerdo -> lado direito Onde o lado esquerdo é um único símbolo e o lado direito é uma sequência de símbolos. Você pode considerar ambos os lados como strings. A forma de usar as regras é substituir as ocorrências do lado esquerdo pelos correspondentes lados direitos. Agora vamos dar uma olhada nessas regras simples em ação, começando a partir do string A: A B Aplique a Regra 1 (A é substituido por B) AB Aplique a Regra 2 (B é substituido por AB) BAB Aplique a Regra 1 para A e então a Regra 2 para B ABBAB Aplique a Regra 2 para B, Regra 1 para A, e Regra 2 para B Observe que cada linha representa uma nova transformação para todo o string. Cada caractere do string original que corresponda a um do lado esquerdo de uma regra foi substituído pelo lado direito correspondente da mesma regra. Depois de fazer a substituição para cada caractere no string original, obtemos o string transformado. Então como podemos codificar essas regras em um programa Python? Há algumas coisas muito importantes a serem observadas aqui:
Vamos dar uma olhada em um programa simples em Python que implementa o exemplo de conjunto de regras descrito acima. def applyRules(ch): newstr = "" if ch == 'A': newstr = 'B' # Rule 1 elif ch == 'B': newstr = 'AB' # Rule 2 else: newstr = ch # no rules apply so keep the character return newstr def processString(oldStr): newstr = "" for ch in oldStr: newstr = newstr + applyRules(ch) return newstr def createLSystem(numIters,axiom): startString = axiom endString = "" for i in range(numIters): endString = processString(startString) startString = endString return endString print(createLSystem(4,"A")) Tente executar o exemplo acima, com valores diferentes para o parâmetro numIters. Você verá que, para os valores 1, 2, 3 e 4, os strings gerados são idênticos aos do exemplo acima. Uma das coisas legais sobre o programa acima é que se você quiser implementar um conjunto diferente de regras, você não precisa re-escrever o programa inteiro. Tudo que você precisa fazer é re-escrever a função applyRules. Suponha que você tenha as seguintes regras:
Que tipo de string seria criado por essa regra? Modifique o programa acima para implementar essa regra. Agora vamos dar uma olhada em um sistema-L real que implementa um desenho famoso. Esse sistema-L possui apenas duas regras:
Esse sistema-L usa símbolos que terão significado especial quando usados para a tartaruga desenhar uma figura.
Essa é a função applyRules para esse sistema-L. def applyRules(ch): newstr = "" if ch == 'F': newstr = 'F-F++F-F' # Rule 1 else: newstr = ch # no rules apply so keep the character return newstr Muito simples até agora. Como você pode imaginar esse string vai ficar muito longo com algumas aplicações das regras. Você pode tentar expandir a cadeia algumas vezes no papel só para ver. O último passo é pegar o string final e transformá-lo em uma figura. Vamos assumir que a tartaruga sempre dá 5 passos para frente ou para trás. Além disso, vamos assumir que a tartaruga sempre gira 60 graus ao virar para a direita ou esquerda. Observe agora o string F-F++F-F. Você pode tentar seguir a explicação acima para ver a figura que este string simples representa. Neste ponto a figura não é grande coisa, mas depois de expandir o string algumas vezes ele vai ficar muito mais interessante. Para criar uma função em Python para desenhar um string vamos escrever uma função chamada drawLsystem. A função terá quatro parâmetros:
Esse é o programa completo em activecode. A função main primeiro cria o string do sistema-L e então cria a tartaruga e passa a tartaruga e o string para a função de desenho. import turtle def createLSystem(numIters,axiom): startString = axiom endString = "" for i in range(numIters): endString = processString(startString) startString = endString return endString def processString(oldStr): newstr = "" for ch in oldStr: newstr = newstr + applyRules(ch) return newstr def applyRules(ch): newstr = "" if ch == 'F': newstr = 'F-F++F-F' # Rule 1 else: newstr = ch # no rules apply so keep the character return newstr def drawLsystem(aTurtle,instructions,angle,distance): for cmd in instructions: if cmd == 'F': aTurtle.forward(distance) elif cmd == 'B': aTurtle.backward(distance) elif cmd == '+': aTurtle.right(angle) elif cmd == '-': aTurtle.left(angle) else: print('Error:', cmd, 'is an unknown command') def main(): inst = createLSystem(4,"F") #create the string print(inst) t = turtle.Turtle() #create the turtle wn = turtle.Screen() t.up() t.back(200) t.down() t.speed(9) drawLsystem(t,inst,60,5) #draw the picture #angle 60, segment length 5 wn.exitonclick() main() Sinta-se a vontade para tentar alguns ângulos e distâncias diferentes para ver como a figura se modifica.
Vamos terminar este capítulo com mais alguns exemplos que mostram variações sobre o tema da iteração pelos dos caracteres de um string. Vamos implementar alguns dos métodos que descrevemos anteriormente para mostrar como eles podem vir a ser. O programa a seguir conta o número de vezes que uma letra em particular, aChar, aparece em um string. É mais um exemplo do padrão de acumulação que vimos nos capítulos anteriores. def count(text, aChar): lettercount = 0 for c in text: if c == aChar: lettercount = lettercount + 1 return lettercount print(count("banana","a")) A função count recebe um string como parâmetro. O comando for itera por cada caractere do string e verifica se o caractere é igual ao valor de aChar. Se igual, a variável de contagem, lettercount, é incrementada. Quando todos os caracteres forem processados, lettercount é retornada.
Essa é uma implementação da função find, que procura um caractere em um string. def find(astring, achar): """ Find and return the index of achar in astring. Return -1 if achar does not occur in astring. """ ix = 0 found = False while ix < len(astring) and not found: if astring[ix] == achar: found = True else: ix = ix + 1 if found: return ix else: return -1 print(find("Compsci", "p")) print(find("Compsci", "C")) print(find("Compsci", "i")) print(find("Compsci", "x")) Num certo sentido, find é o oposto do operador de indexação. Em vez de receber um índice e extrair o caractere correspondente, ela pega um caractere e encontra o índice onde esse caractere aparece pela primeira vez. Se o caractere não for encontrado, a função retorna -1. O laço while neste exemplo usa uma condição um pouco mais complexa do que temos visto em programas anteriores. Aqui há duas partes para a condição. Queremos continuar se houver mais caracteres para serem olhados e queremos continuar caso ainda não tenhamos encontrado o que estamos procurando. A variável found é uma variável booleana que controla se já encontramos o caractere que estamos procurando. Ele é inicializado com False. Se encontrarmos o caractere, found recebe True. A outra parte da condição é a mesma que foi utilizada anteriormente para percorrer os caracteres do string. Como combinamos essas duas partes com um operador lógico and, é necessário que ambas as partes sejam True para continuar a iteração. Se uma parte falhar, a condição falha e a iteração pára. Quando a iteração pára, nós simplesmente fazemos uma pergunta para descobrir o porquê e, em seguida, retornamos o valor adequado.
Note Esse padrão de computação é chamado às vezes de percurso eureka pois assim que encontramos o que estamos procurando podemos gritar Eureka! e parar de procurar. A forma de parar de procurar é alterando o valor de found para True, que causa a falha na condição.
Para encontrar a posição da segunda ou terceira ocorrência de um caractere em um string nós podemos modificar a função find, adicionando um terceiro parâmetro para a posição inicial no string de busca: def find2(astring, achar, start): """ Find and return the index of achar in astring. Return -1 if achar does not occur in astring. """ ix = start found = False while ix < len(astring) and not found: if astring[ix] == achar: found = True else: ix = ix + 1 if found: return ix else: return -1 print(find2('banana', 'a', 2)) A chamada find2('banana', 'a', 2) agora retorna 3, o índice da primeira ocorrência de ‘a’ em ‘banana’ depois do índice 2. O que é retornado pela chamada find2('banana', 'n', 3)? Se você respondeu 4, há uma boa chance que você tenha entendido como find2 funciona. Experimente. Melhor ainda, podemos combinar find e find2 usando um parâmetro opcional. def find3(astring, achar, start=0): """ Find and return the index of achar in astring. Return -1 if achar does not occur in astring. """ ix = start found = False while ix < len(astring) and not found: if astring[ix] == achar: found = True else: ix = ix + 1 if found: return ix else: return -1 print(find3('banana', 'a', 2)) A chamada find3('banana', 'a', 2) para essa versão de find se comporta da mesma forma que find2, enquanto na chamada find3('banana', 'a'), start receberá o valor default de 0. Adicionando um outro parâmetro opcional em find permite que a busca seja feita a partir de uma posição inicial (start), até mas não incluindo a posição final (end). def find4(astring, achar, start=0, end=None): """ Find and return the index of achar in astring. Return -1 if achar does not occur in astring. """ ix = start if end == None: end = len(astring) found = False while ix < end and not found: if astring[ix] == achar: found = True else: ix = ix + 1 if found: return ix else: return -1 ss = "Python strings have some interesting methods." print(find4(ss, 's')) print(find4(ss, 's', 7)) print(find4(ss, 's', 8)) print(find4(ss, 's', 8, 13)) print(find4(ss, '.')) O valor opcional para end é interessante. Nós damos um valor default None se o chamador não fornecer esse argumento. No corpo da função testamos o valor de end e, caso seja None, vamos atribuir o comprimento do string para end. No entanto, se o chamador tiver fornecido um argumento para end, o valor do chamador será utilizado no laço. A semântica de start e end nessa função é precisamente a mesma usada na função range.
Muitas vezes, é útil examinar um caractere e testar se ele é maiúsculo ou minúsculo, ou se é uma letra ou um dígito. O módulo string fornece várias constantes que são úteis para esses fins. Uma delas, string.digits é equivalente a “0123456789”. Ela pode ser usada para verificar se um caractere é um dígito usando o operador in. O string string.ascii_lowercase contém todas as letras ASCII que o sistema considera serem minúsculas. Da mesma forma, string.ascii_uppercase contém todas as letras maiúsculas. string.punctuation contem todos os caracteres considerados símbolos de pontuação. Experimente o seguinte e veja o que acontece. print(string.ascii_lowercase) print(string.ascii_uppercase) print(string.digits) print(string.punctuation) Para mais informações consulte a documentação do módulo string (veja Global Module Index).
Esse capítulo introduziu várias novas ideias. O seguinte resumo pode ser-lhe útil para lembrar o que você aprendeu. indexação ([])Acessa um único caractere em um string usando sua posição (com início em 0). Exemplo: 'Isso'[2] resulta em 's'. função len (comprimento)Retorna o número de caracteres em um string. Exemplo: len('happy') resulta em 5. percurso do laço for (for)Percorrer um string significa acessar cada caractere no string, um de cada vez. Por exemplo, o seguinte laço for: executa o corpo do laço 7 vezes com diferentes valores de ix a cada vez. fatiamento ([:])Uma fatia (slice) é um substring de um string. Exemplo: 'sorvete de banana'[3:6] resulta em vet. comparação de strings (>, <, >=, <=, ==, !=)Os seis operadores relacionais (de comparação) comuns funcionam com strings e são avaliados de acordo com a ordem lexicográfica. Exemplos: 'apple' < 'banana' resulta em True. 'Zeta' < 'Appricot' resulta em False. 'Zebra' <= 'aardvark' resulta em True pois todas as letras maiúsculas precedem as minúsculas. operadores in e not in (in, not in)O operador in testa se um string está contido em outro. Exemplos: 'curar' in "Eu vou procurar voce." resulta em True. 'curdado' in "Eu vou procurar voce." resulta em False. branco (whitespace) Qualquer caractere que move o cursor sem imprimir caracteres visíveis. A constante string.whitespace contém todos os caracteres “brancos”. fatiaUma parte de um string (substring) especificado por um intervalo de índices. De forma mais genérica, uma subsequência de qualquer tipo de sequência em Python pode ser criada usando o operador de fatia (sequencia[inicio:fim]). imutávelUm tipo de dado composto cujos elementos não podem receber novos valores. índiceUma variável ou valor usado para selecionar um membro de uma coleção ordenada, como um caractere em um string, ou um elemento de uma lista. notação pontoUso do operador ponto, ., para acessar funções dentro de um módulo, ou acessar métodos e atributos de um objeto. parâmetro opcionalUm parâmetro definido no cabeçalho de uma função com a atribuição de um valor default que ele receberá caso nenhum argumento correspondente seja fornecido na chamada da função. percursoPara iterar pelos elementos de uma coleção, realizando uma operação similar para cada elemento. tipo de dado coletivoUm tipo de dado no qual os valores são constituidos por componentes, ou elementos, que são valores. valor defaultO valor dado para um parâmetro opcional caso nenhum argumento seja fornecido na chamada.
|