#! /usr/bin/env python2.6 # -*- coding: utf-8 -*- #--------------------------------- # Editado: #Autor: Erickson Silva #Email: #LAViD - Laboratório de Aplicações de Vídeo Digital #--------------------------------- # Donatus Brazilian Portuguese Parser # # Copyright (C) 2010-2013 Leonel F. de Alencar # # Author: Leonel F. de Alencar # Homepage: # # Project's URL: # For license information, see LICENSE.TXT # # $Id: alexp.py $ """Este módulo contém funções que permitem utilizar o Aelius para etiquetar uma sentença, construindo entradas lexicais com base nas etiquetas atribuídas às palavras da sentença. Essas entradas lexicais são integradas em uma gramática CFG dada, que é transformada em um parser, utilizado para gerar uma árvore de estrutura sintagmática da sentença. """ import re, string,nltk,os from Aelius.Extras import carrega from Aelius import AnotaCorpus # definição de algumas variáveis globais para # facilitar utilização das diferentes funções do módulo # sintaxe default em subpasta de nltk_data DIR="/vlibras-translate/data/cfg.syn.nltk" # eventualmente será preciso incluir aqui outros sinais # de pontuação, como o travessão PUNCT=string.punctuation SENTENCA_ANOTADA="" def toqueniza(s): """Decodifica string utilizando utf-8, retornando uma lista de tokens em unicode. """ decodificada=s.decode("utf-8") return AnotaCorpus.TOK_PORT.tokenize(decodificada) def getAnaliseMorfologica(): return SENTENCA_ANOTADA def etiquetaSentenca(s): """Aplica um dos etiquetadores do Aelius na etiquetagem da sentença dada como lista de tokens. """ etiquetador = carrega("AeliusHunPos") anotada = AnotaCorpus.anota_sentencas([s],etiquetador,"hunpos")[0] return anotada def geraEntradasLexicais(lista): """Gera entradas lexicais no formato CFG do NLTK a partir de lista de pares constituídos de tokens e suas etiquetas. """ entradas=[] for e in lista: # é necessário substituir símbolos como "-" e "+" do CHPTB # que não são aceitos pelo NLTK como símbolos não terminais c=re.sub(r"[-+]","_",e[1]) c=re.sub(r"\$","_S",c) entradas.append("%s -> '%s'" % (c, e[0].lower())) return entradas def corrigeAnotacao(lista): """Esta função deverá corrigir alguns dos erros de anotação mais comuns do Aelius. No momento, apenas é corrigida VB-AN depois de TR. """ i=1 while i < len(lista): if lista[i][1] == "VB-AN" and lista[i-1][1].startswith("TR"): lista[i]=(lista[i][0],"VB-PP") i+=1 # a função abaixo parece muito restritiva; talvez não seja necessário # que o arquivo esteja no diretório nltk_data def encontraArquivo(caminho=DIR): """Encontra arquivo na pasta vlibras-translate. """ home = os.path.expanduser("~") path = os.path.realpath(home+caminho) return path def extraiSintaxe(caminho=DIR): """Extrai gramática armazenada em arquivo cujo caminho é definido relativamente ao diretório nltk_data. """ arquivo=encontraArquivo(caminho) if arquivo: f=open(arquivo,"rU") sintaxe=f.read() f.close() return sintaxe else: print "Arquivo %s não encontrado em nenhum dos diretórios de dados do NLTK:\n%s" % (caminho,"\n".join(nltk.data.path)) def analisaSentenca(sentenca): """Retorna lista de árvores de estrutura sintagmática para a sentença dada sob a forma de uma lista de tokens, com base na gramática CFG cujo caminho é especificado como segundo argumento da função. Esse caminho é relativo à pasta nltk_data da instalação local do NLTK. A partir da etiquetagem morfossintática da sentença são geradas entradas lexicais que passam a integrar a gramática CFG. O caminho da gramática e o parser gerado são armazenados como tupla na variável ANALISADORES. """ parser=constroiAnalisador(sentenca) codificada=[w.encode("utf-8") for w in sentenca] trees=parser.parse_one(codificada) return trees def constroiAnalisador(s): """Constrói analisador a partir de uma única sentença não anotada, dada como lista de tokens, e uma lista de regras sintáticas no formato CFG, armazenadas em arquivo. Esta função tem um bug, causado pela maneira como o Aelius etiqueta sentenças usando o módulo ProcessaNomesProprios: quando a sentença se inicia por paravra com inicial minúscula, essa palavra não é incorporada ao léxico, mas a versão com inicial maiúscula. """ global SENTENCA_ANOTADA SENTENCA_ANOTADA=etiquetaSentenca(s) corrigeAnotacao(SENTENCA_ANOTADA) entradas=geraEntradasLexicais(SENTENCA_ANOTADA) lexico="\n".join(entradas) gramatica="%s\n%s" % (extraiSintaxe(DIR).strip(),lexico) cfg=nltk.CFG.fromstring(gramatica) return nltk.ChartParser(cfg) def exibeArvores(arvores): """Função 'wrapper' para a função de exibição de árvores do NLTK""" nltk.draw.draw_trees(*arvores) def run(sentenca): tokens=toqueniza(sentenca) trees=analisaSentenca(tokens) return trees