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

Date: 2018-11-25 zo 00:00

Author: Andrew

Other posts