:root…blog:

this is my home… my ideas… my thoughts… my life…

Archive for the ‘regular expressions’ tag

Insônia novamente

with 2 comments

Apesar de estar morrendo de cansaço, não consigo dormir. Já li, já escutei música, já fiquei no escuro. Nada. Então resolvi vir para o computador, esperar o sono chegar e enquanto navegava por aí, encontrei este post, do Walter Cruz, falando sobre o exercício Text Munger, postado aqui.

Primeiro, resolvi fazer uma solução “simples”, sem muita sofisticação, lendo os dados de um arquivo de texto para uma unicode string e correndo dois ponteiros sobre esta, indicando o início e o final de cada palavra - basta então chamar a função que “bagunça” os caracteres entre os dois ponteiros.

def MungeWord(word):
  if len(word) <= 2:
    return word
  first = word[0]
  last = word[-1]
  middle = list(word[1:-1])
  random.shuffle(middle)
  return ''.join((first, ''.join(middle), last))

def MungeFile(all_data):
  result = []
  index = 0
  while index < len(all_data):
    while index < len(all_data) and not all_data[index].isalpha():
      result.append(all_data[index])
      index += 1
    end = index + 1
    while end < len(all_data) and all_data[end].isalpha():
      end += 1
    result.append(MungeWord(all_data[index:end]))
    index = end
  return result

A segunda idéia é praticamente igual a primeira, mas, ao invés de utilizar dois índices, vou utilizar o método pop das listas para ler os caracteres.

def MungeWord(word):
  if len(word) <= 2:
    return word
  word = list(word)
  first = word.pop(0)
  last = word.pop()
  random.shuffle(word)
  return ''.join((first, ''.join(word), last))

def MungeFile(all_data):
  all_data = list(all_data)
  result = []
  if len(all_data) <= 2:
    return result
  char = all_data.pop(0)
  while all_data:
    word = []
    while all_data and char.isalpha():
      word.append(char)
      char = all_data.pop(0)
    result.append(MungeWord(''.join(word)))
    while all_data and not char.isalpha():
      result.append(char)
      char = all_data.pop(0)
  return result

A terceira e a quarta idéias já utilizam regular-expressions - como o Walter queria. No entanto, vale ressaltar um detalhe: \w, em Python, considera números e underscores como sendo partes válidas de uma palavra, o que não era desejado no exercício. No entanto, como o próprio Matthew Moss escreveu, muitos escolhem usar \w então consideraremos estas soluções aceitáveis.

A terceira implementação utiliza o conceito de split ou, quebra, da string em diversos elementos de uma lista, de acordo com a expressão regular separadora.

def MungeWord(word):
  if not word or not word[0].isalpha() or len(word) <= 2:
    return word
  middle = list(word[1:-1])
  random.shuffle(middle)
  return ''.join((word[0], ''.join(middle), word[-1]))

def MungeFile(all_data):
  regex = re.compile(r"(\W+)", re.UNICODE)
  words = regex.split(all_data)
  result = []
  while words:
    word = words.pop(0)
    result.append(MungeWord(word))
  return result

Já a quarta implementação utiliza o método sub das expressões regulares em Python, para executar uma função de substituição sobre cada uma das ocorrências da expressão em si.

def MungeWord(match):
  word = match.group()
  if len(word) <= 2:
    return word
  middle = list(word[1:-1])
  random.shuffle(middle)
  return ''.join((word[0], ''.join(middle), word[-1]))

def MungeFile(all_data):
  regex = re.compile(r"\w+", re.UNICODE)
  all_data = regex.sub(MungeWord, all_data)
  return all_data

Vamos comparar então. Primeiro com um texto pequeno, 1KB:

         226 function calls in 0.003 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.001    0.001    0.003    0.003 /home/rodolpho/text_munger.py:19(MungeFile)

         225 function calls in 0.004 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.002    0.002    0.004    0.004 /home/rodolpho/text_munger2.py:19(MungeFile)

         424 function calls (418 primitive calls) in 0.003 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.001    0.001    0.003    0.003 /home/rodolpho/text_munger3.py:20(MungeFile)

         272 function calls (270 primitive calls) in 0.003 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.003    0.003 /home/rodolpho/text_munger4.py:19(MungeFile)

Aparentemente, com arquivos pequenos, a diferença em tempo de execução é mínima entre as implementações. Vamos agora jogar um arquivo maior: 3,9MB.

         1389493 function calls in 10.116 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    3.990    3.990   10.116   10.116 /home/rodolpho/text_munger.py:19(MungeFile)

         1389492 function calls in 15296.867 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1 15269.408 15269.408 15296.867 15296.867 /home/rodolpho/text_munger2.py:19(MungeFile)

         2157415 function calls (2157409 primitive calls) in 1301.620 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1 1282.561 1282.561 1301.620 1301.620 /home/rodolpho/text_munger3.py:18(MungeFile)

         1389538 function calls (1389536 primitive calls) in 8.105 CPU seconds
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    1.530    1.530    8.105    8.105 /home/rodolpho/text_munger4.py:19(MungeFile)

Opa! Agora sim vários resultados interessantes. De cara vemos que solução de usar substitution com expressões regulares apresentou os melhores resultados (oito segundos e pouco, para quase 4MB de texto é um bom resultado). Além disso, vemos que a primeira solução (com os índices) também não ficou tão atrás assim.

A surpresa vem com a segunda idéia: certa de 15297 segundos??? Sim, demorou mais de 4 horas para executar na minha máquina e parece ser uma implementação tão simples, senão mais, que a primeira. Nem tudo que parece simples, é.

A terceira idéia apresentou um resultado tão bom quanto a primeira, o que é uma certa surpresa - eu esperava ver os resultados com regular expressions serem bem melhores do que os demais.

Eu preciso correr para uma consulta médica que tenho e não posso explicar agora os motivos de tais resultados. Prometo que escreverei um post ainda mais longo sobre isso, com gráficos e tudo mais, estudando tanto a função MungeWord como a MungeFile. (Para quem tem muita pressa, uma dica).

Beijos e Abraços! Bom dia!

Written by rootguy

July 3rd, 2008 at 6:43 am

PyCon 2008 - 2o dia

with 3 comments

Como eu tinha previsto, o segundo dia foi tão cheio de conteúdo quanto o primeiro. O número de presentes também aumentou, o que pude observar pela quantidade de mesas que precisaram montar nos corredores para que todos pudessem almoçar sentados.

A primeira palestra do dia, na verdade, foi um anúncio do time do Twisted (site). Honestamente, eu nunca tinha ouvido falar neste projeto - apesar de, pelos comentários dos outros, ser um dos projetos mais antigos da comunidade Python. Realmente algo que eu preciso estudar.

Twisted

Em seguida, houve a apresentação do Brian “Fitz”, gerente de engenharia do Google aqui em Chicago. O título da apresentação foi o primeiro de diversos títulos interessantes e um tanto quanto “misteriosos” que tivemos hoje: “You can fool all the people all of the time” (”Você consegue enganar todas as pessoas o tempo todo”, uma piada com o ditado: “Você pode enganar algumas pessoas o tempo todo ou você pode enganar todas as pessoas por algum tempo, mas você não consegue enganar todas as pessoas o tempo todo”). Eu escreveria aqui uma explicação sobre a palestra do Fitz, mas como ele possivelmente vá dar essa palestra para o GruPy-SP, no dia 24, não vou estragar a surpresa :P Caso ele não possa participar da reunião do GruPy-SP, então eu publico em um outro post.

Fitz

A apresentação seguinte foi do Van Lindberg, um advogado, chamada “Propriedade Intelectual e Código Aberto” (original: “Intellectual Property and Open Source“). Ele começou por mostrar qual foi a origem das leis de IP (propriedade intelectual, em inglês) e o porque das necessidades delas.

Van Lindberg

Realmente foi uma apresentação muito boa, porque muita gente que conheço, e trabalha com open source, prega contra leis de direitos autorais na área de software, afirmando que o bem geral da sociedade só pode surgir com sistemas de código aberto etc. Van Lindberg mostrou claramente, usando até explicação matemática (com teoria de jogos), que o caso não é tão simples assim.

Na verdade, o GPL e outras licenças do tipo só existem porque as leis de IP regulamentam o setor, senão elas nem poderiam existir. Apesar do conteúdo extremamente focado para o domínio jurídico americano - não preciso explicar porque -, essa palestra, quando estiver disponível em vídeo, será recomendada por mim para diversos amigos evangelizadores de “anarquia tecnológica”.

Bom, encerrando a palestra que já estava deixando diversos presentes sem paciência (alguns começaram a reclamar no canal de IRC imediatamente quando souberam que um advogado estava falando), voltamos às apresentações técnicas. A próxima foi do Rodney Drenth que falou sobre como implementar máquinas de estados finitas utilizando decoradores de Python.

MEF

Infelizmente, o apresentador demorou demais para pegar o ritmo do assunto e acabou gastando muito tempo falando sobre MEF (acredito que ninguém no PyCon precisa de explicações detalhadas sobre o que são, como funcionam e pra que servem, porque todos já estudamos isso alguma vez na vida) e pouco tempo sobre a implementação de fato. Essa é mais uma apresentação que terei que reler o material sozinho no futuro.

Para quem gosta de complexidade de sistemas, testes e métricas para isso, a quinta palestra do dia foi um prato cheio. Apresentada por Matt Harrison, ela não tratou de análise de complexidade algorítmica (a notação do O), mas de uma análise mais simplificada do código-fonte com implicações em situações mais tangíveis no dia-a-dia da platéia como manutenção de código alheio, por exemplo. Infelizmente, eu não tenho um link para o material que ele utilizou durante a apresentação, mas vou ficar de olho - vale a pena ter como referência futura, principalmente por citar algumas ferramentas simples que alertam para problemas complexos que passam despercebidos (por algum tempo).

E para encerrar a manhã, tivemos a palestra do Alex Martelli sobre como trabalhar com callbacks em Python (essa palestra também teve um título interessante: “Don’t call us, we’ll call you” - “Não nos chame, nós chamaremos você”). Essa é uma palestra que os presentes no encontro do GruPy-SP, no dia 24, poderão assistir diretamente do Alex, então, para não estragar o conteúdo, vou segurar um post sobre o conteúdo até depois dessa reunião.

Alex Martelli

De qualquer maneira, não preciso nem falar que o modo de apresentar e o conteúdo que o Alex possui é indescritível, realmente vale a pena.

Após o almoço e uma breve pausa para o descanso mental, voltei para a terceira palestra com título engraçado: “Using Grok to walk like a duck” (”Usando Grok para andar como um pato”). Cheguei ao auditório sem saber ao certo o que esperar, só sabia que o Grok é um framework web, em Python, baseado em alguns módulos do Zope - até aí, como isso me faria andar como um pato continuava um mistério.

A apresentação do Brandon Rhodes (aqui) começou lembrando um raciocínio estabelecido pelo Alex Martelli (da palestra anterior) sobre os “tipos de variáveis” em Python: “Anda como um pato? Faz quack como um pato? Então deve ser um pato”. Isso aplicado às variáveis, diz que, apesar de não saber exatamente qual o tipo de uma delas, o programador assume que ela se comporta de determinada maneira, ou seja, você nunca sabe se, de fato, é um pato, você simplesmente sabe que se comporta como um.

O assunto da palestra então se tornou mais claro. Era sobre como você pode fazer certos objetos se comportarem de maneiras específicas, de modo a se passarem por um tipo diferente do que realmente são. E ele demonstrou como isso pode ser feito, principalmente na construção de middlewares, com Grok.

As duas últimas apresentações que eu assisti no dia tinham conteúdos técnicos mais leves. :)

A primeira delas, por Steven Wilcox, foi sobre como utilizar o módulo de administração do django, mesmo em projetos não desenvolvidos neste framework. Parece um tanto quanto bizarra a idéia e só quando ele começou a falar que entendi o que ele quis dizer.

Se você ler o material dele (aqui), verá que o que ele fez foi um hack bem interessante. Para conversar com um sistema legado dele, ele construiu um aplicativo django, com interface direta no banco-de-dados legado (apesar de sugerir não fazer isso e colocar alguns scripts de sincronização entre os bancos), no qual ele só utilizou o módulo de admin. Agora isso é a lei de mínimo esforço haha!

E a última palestra do dia foi feita pela esposa do Alex (sim, o mesmo da palestra acima), Anna Ravenscroft. O tema foi Regular Expressions: “To RE or not to RE“. O marido da palestrante publicou há pouco tempo um artigo analisando exatamente esse assunto, quando utilizar e quando não utilizar RE; apresentando resultados de benchmarks para convencer o leitor sobre seu argumento. O que eu esperava era uma apresentação ao vivo deste artigo.

Foi uma versão mais light (aqui). Tratando sobre casos quando não utilizar, Anna apresentou algumas situações para evitar REs. Se você quiser mais conteúdo, recomendo mesmo ler o artigo do Alex.

Bom, isso foi um “resumo” do que foram as principais apresentações do dia. Além delas, ocorrem incontáveis conversas nos corredores, micro-apresentações nas salas e trocas de informação informais por aí, não dá para resumir ou escrever sobre essas coisas - é preciso estar aqui.

Hoje também houve a primeira reunião para a organização do PyCon 2010! Sim, 2010. Dá para acreditar que eles estão trabalhando já em um evento que acontecerá somente em 2 anos? Só assim para entender a qualidade da organização!

Amanhã é o último dia de palestras e a transição para os dias de sprint que aconteceram aqui em Chicago. Voltarei com mais um resumo do dia aqui ;)

Saudades ainda maiores do meu amor, minha namorada! Mas falta menos de uma semana para retornar ao Brasil!

Beijos e abraços!