Parlare come Yoda tu puoi
Non avendo molto da fare in questo fine settimana, ed essendo il tempo non dei migliori, ho deciso di pensare a qualche piccolo progetto divertente e di poche righe. Ed ecco che il risultato è stato una breve funzione che trasforma le frasi da SVO ad OSV, da come parliamo noi e gli Inglesi a come parla Yoda.
Yodinator
Per questo progetto ho usato solo due funzioni di NLTK: pos_tag e word_tokenize. La prima per taggare le frasi, la seconda per tokenizzarle.
from nltk import pos_tag, word_tokenize
Per prima cosa la funzione prende come unico argomento una stringa, dopo di che tokenizza la stringa ed applica il part-of-speech tagger sulla lista di parole.
La dinamica si baserà sul prendere gli avverbi ed i verbi come fulcro (o i verbi modali/ausiliari in caso ci siano). Per far ciò si dichiara preventivamente un tuple di tag contenente tutte le tag dei verbi.
Per avere una lista delle tag presenti in pos_tag basta importare nltk e poi usare la funzione help.upenn_tagset().
I verbi sono il fulcro perchè sono il punto in cui separeremo la frase a metà e la invertiremo. Ovviamente questo rende possibile "yodizzare" solo frasi molto semplici e soprattutto affermative. E' Domenica e quindi ci si accontenta.
Le dichiarazioni delle variabili terminano con le liste vuote della prima metà della frase e della seconda metà che andremo a riempire.
def yodinator(text): text = word_tokenize(text) tagged = pos_tag(text) verbs = ("MD", "VB", "VBD", "VBG", "VBN", "VBP", "VBZ", "RB", "RBR", "RBS") adverbs = ("RB", "RBR", "RBS") first_half = [] second_half = []
Adesso che la frase è taggata e abbiamo le definizioni delle part of speech pronte, la funzione controlla ogni tuple prodotto dalla funzione pos_tag() in un for loop.
Questo loop userà come variabile l'index della lista di touple tagged. Se il secondo elemento di un touple è un verbo, allora la frase verrà divisa in quel punto. Se anche l'elemento successivo è un verbo o avverbio, allora il primo verbo diventerà comunque il fulcro.
for t in range(0, len(tagged)): if tagged[t][1] in verbs and not tagged[t+1][1] in verbs: first_half.extend(tagged[:t+1]) second_half.extend(tagged[t+1:]) break elif tagged[t][1] in verbs and tagged[t+1][1] in verbs: first_half.extend(tagged[:t+1]) second_half.extend(tagged[t+1:]) break
In seguito, la funzione unisce le due liste di touple, rimuove la punteggiatura e fissa il punto interrogativo, se presente, alla fine della frase.
Infine, la lista di parole viene riunita in un'unica stringa.
sentence1 = second_half + first_half sentence = [item[0] for item in sentence1 if item[0] not in (".",",")] if "?" in sentence: sentence.append(sentence.pop(sentence.index("?"))) sentence = " ".join(sentence) return sentence
Si può provare questa funzione con liste di frasi random (se ne trovano parecchie in formato txt su github) per vederne i risultati.
Le frasi più lunghe saranno mal elaborate, soprattutto se hanno più di un periodo, e le domande a volte avranno un ordine molto confuso, ma semplici frasi affermative daranno spesso il risultato desiderato.
- goodbye to them before they leave Go say
- now worse Matters are
- Canadian I am
- special I am
- nervous about Fido The mailmen are
- you The zombies miss
- some strange ideas It has
- a new camera I got
- for the job Tom applied
La versione intera del codice si trova qui