word_tokenize tokens tokenizer tokenization tokenizacion spanish example python regex token tokenize nltk

tokens - Escribiendo un tokenizador en Python



tokens python example (2)

Quiero diseñar un módulo tokenizer personalizado en Python que permita a los usuarios especificar qué tokenizer (s) usar para la entrada. Por ejemplo, considere la siguiente entrada:

P: ¿Cuál es una buena manera de lograr esto? A: No estoy tan seguro. Creo que usaré Python.

Quiero poder proporcionar la tokenización de oraciones de sent_tokenize() , sent_tokenize() como una opción porque funciona bien en muchas situaciones y no quiero reinventar la rueda. Además de esto, también quiero proporcionar un generador de tokenización más detallado (algo parecido a un motor de reglas). Dejame explicar:

Supongamos que ofrezco un par de tokenizadores:

SENTENCE # Tokenizes the given input by using sent_tokenize() WORD # Tokenizes the given input by using word_tokenize() QA # Tokenizes using a custom regular expression. E.g., Q: (.*?) A: (.*?)

Quiero apoyar las reglas de la siguiente manera:

  1. QA -> SENTENCE: Primero aplique el tokenizer QA, seguido del tokenizer de la oración
  2. Control de calidad: aplique solo el tokenizador de control de calidad

Por lo tanto, la salida esperada es la siguiente:

1. QA -> SENTENCIA

[ (''QUESTION'', (''SENTENCE'', ''What is a good way to achieve this?''), ), (''ANSWER'', (''SENTENCE'', ''I am not so sure'', ''I think I will use Python'') ) ]

2. QA

[ (''QUESTION'', ''What is a good way to achieve this?''), (''ANSWER'', ''I am not so sure. I think I will use Python'') ]

¿Qué es un buen diseño para lograr esto de manera eficiente?


Como la tokenización es fácil en Python, me pregunto qué planea proporcionar su módulo. Me refiero a que al iniciar una pieza de software, un buen diseño proviene de pensar en los escenarios de uso que de considerar primero las estructuras de datos.

Sus ejemplos para la salida esperada son un poco confusos. Supongo que desea que los tokenizadores devuelvan el nombre en el lado izquierdo y una lista de tokens en el lado derecho. Jugué un poco para lograr resultados similares, pero utilizando listas para un manejo más sencillo:

import re # some tokenizers def tokzr_WORD(txt): return (''WORD'', re.findall(r''(?ms)/W*(/w+)'', txt)) # split words def tokzr_SENT(txt): return (''SENTENCE'', re.findall(r''(?ms)/s*(.*?(?:/.|/?|!))'', txt)) # split sentences def tokzr_QA(txt): l_qa = [] for m in re.finditer(r''(?ms)^[/s#/-/*]*(?:Q|Question)/s*:/s*(?P<QUESTION>/S.*?/?)[/s#/-/*]+(?:A|Answer)/s*:/s*(?P<ANSWER>/S.*?)$'', txt): # split (Q, A) sequences for k in [''QUESTION'', ''ANSWER'']: l_qa.append(m.groupdict()[k]) return (''QA'', l_qa) def tokzr_QA_non_canonical(txt): # Note: not supported by tokenize_recursively() as not canonical. l_qa = [] for m in re.finditer(r''(?ms)^[/s#/-/*]*(?:Q|Question)/s*:/s*(?P<QUESTION>/S.*?/?)[/s#/-/*]+(?:A|Answer)/s*:/s*(?P<ANSWER>/S.*?)$'', txt): # split (Q, A) sequences for k in [''QUESTION'', ''ANSWER'']: l_qa.append((k, m.groupdict()[k])) return l_qa dict_tokzr = { # control string: tokenizer function ''WORD'' : tokzr_WORD, ''SENTENCE'': tokzr_SENT, ''QA'' : tokzr_QA, } # the core function def tokenize_recursively(l_tokzr, work_on, lev=0): if isinstance(work_on, basestring): ctrl, work_on = dict_tokzr[l_tokzr[0]](work_on) # tokenize else: ctrl, work_on = work_on[0], work_on[1:] # get right part ret = [ctrl] if len(l_tokzr) == 1: ret.append(work_on) # add right part else: for wo in work_on: # dive into tree t = tokenize_recursively(l_tokzr[1:], wo, lev + 1) ret.append(t) return ret # just for printing def nestedListLines(aList, ind='' '', d=0): """ Returns multi-line string representation of /param aList. Use /param ind to indent per level. """ sRet = ''/n'' + d * ind + ''['' nested = 0 for i, e in enumerate(aList): if i: sRet += '', '' if type(e) == type(aList): sRet += nestedListLines(e, ind, d + 1) nested = 1 else: sRet += ''/n'' + (d + 1) * ind + repr(e) if nested else repr(e) sRet += ''/n'' + d * ind + '']'' if nested else '']'' return sRet # main() inp1 = """ * Question: I want try something. Should I? * Answer : I''d assume so. Give it a try. """ inp2 = inp1 + ''Q: What is a good way to achieve this? A: I am not so sure. I think I will use Python.'' print repr(tokzr_WORD(inp1)) print repr(tokzr_SENT(inp1)) print repr(tokzr_QA(inp1)) print repr(tokzr_QA_non_canonical(inp1)) # Really this way? print for ctrl, inp in [ # example control sequences (''SENTENCE-WORD'', inp1), (''QA-SENTENCE'', inp2) ]: res = tokenize_recursively(ctrl.split(''-''), inp) print nestedListLines(res)

Por cierto Python / Lib / tokenize.py (para el código Python en sí mismo) podría ser útil para manejar las cosas.


Si entiendo la pregunta correctamente, creo que deberías reinventar la rueda. Implementaría máquinas de estado para los diferentes tipos de tokenización que desea y usaría los diccionarios de Python para guardar los tokens.

http://en.wikipedia.org/wiki/Finite-state_machine

Ejemplo de máquina de estados que toma una oración con espacios e imprime las palabras, por supuesto, ¡podría hacer este ejemplo específico de una manera más fácil! ¡Pero con las máquinas estatales en general, obtiene un rendimiento de tiempo lineal y puede personalizarlo fácilmente!

while 1: if state == "start": if i == len(text): state = "end" elif text[i] == " ": state = "new word" i = i - 1 else: word.append(text[i]) elif state == "new word": print(''''.join(word)) del word[:] state = "start" elif state == "end": print(''''.join(word)) break i = i + 1

http://docs.python.org/2/library/collections.html#collections.Counter

Luego, por ejemplo, puedes usar esta estructura de datos de Python para guardar tus tokens. Creo que es perfectamente adecuado para sus necesidades!

Espero que esto haya sido de alguna ayuda.