PyPills – Lezione 2 – Stream, parsing and many more!


Buongiorno a tutti. Oggi vi voglio parlare di come è fatto un processo. Potete immaginare un processo come una scatola nera o meglio ancora, per chi ha fatto un minimo di elettronica, come un tripolo (sennò cercate transistor su wikipedia).

Un processo nasce, cresce e muore con 3 stream “attaccati” ad esso:

Stdin, anche noto come Standard Input, è lo stream da cui il processo legge gli input provenienti dall’ esterno, tipicamente dall’ utente che l’ha lanciato o da un altro programma.

Stdout, anche noto come Standard Output, è lo stream di dati che un processo produce alla fine del suo job, volgarmente detto risultato.

Stderr, anche noto come Standard Error è lo stream in cui il programma “vomita” eventuali codici d’errore a seguito di un comportamento inaspettato.

Perchè vi dico tutto questo? Il python nasce come glue, come colla, è infatti molto usato come collante tra vari programmi. Fortunatamente per noi esiste una tecnica nota come pipelining che permette di destinare lo stdout di un processo A come stdin di un altro processo, creano cosi vere e proprie pipeline (catene di montaggio). Chi ha familiarità con il mondo Unix non si stupirà delle mie parole. Un esempio?

cat /etc/pippo.txt | wc -l

Cosa abbiamo fatto? Abbiamo letto un file con cat e abbiamo mandato lo stdout di cat in input a wc, che ci ha calcolato il numero di linee del nostro file di testo. Ma ora veniamo al python.

Su Python-it.org si era intavolata una conversazione su come fosse possibile recuperare le informazioni da un file, ad esempio come da un file MP3 fosse possibile recuperare le ID3. L’utente Flame_Alchemist, che ringrazio, ha fatto osservare che tali info, qualora presenti, risiedono nei primi 128 byte del file Mp3.

Ecco allora l’idea: sfruttiamo un tool Unix chiamato hexdump (calma Linuxofili, funziona anche da voi 😀 ) che permette di fare il dump esadecimale di qualsiasi file e poi, col nostro amato Python, ci andiamo a recuperare le informazioni che vogliamo. E’ rozzo e probabilmente non lo userete mai, l’ho scritto solo per farvi vedere due cose:

-Come sia possibile gestire il pipeline in un programma python

-Uno studio di caso di come si realizza un banale parser a partire da un dump esadecimale.

import sys

import os

class Id3Parser:

    def __init__(self):

        self.input = str.split(str.rstrip(sys.stdin.read()),"\n")

    def get_char_list(self):

        '''Ritorna il dump cosi come e' stato preso in stdin, ogni carattere

        rappresenta una cifra esadecimale'''

        return self.input

    def get_hex_list(self):

        '''Permette di ottenere una lista con il valore decimale di tutti

        i caratteri esadecimale presi da stdin'''

        hex_list = [self.hexstr2ascii(el) for el in self.input]

        return hex_list

    def get_ascii_list(self):

        '''Questa funzione preso un valore decimale ne trova il corrispettivo

        valore ascii, comprimento la lista in modo che i caratteri non ascii

        (minori di 32 in decimale) facciano da spaziatore tra un carattere

        valido e l'altro'''

        lst =[]

        prev=0

        for el in self.get_hex_list():

            if el < 32 and prev < 32:

                continue

            elif el < 32 and prev > 32:

                lst.append("00")

            else:

                lst.append(chr(el))

            prev = el

        return lst

    def hexstr2ascii(self, value):

        '''Questa funzione, preso un qualsiasi valore ascii rappresentante un

        esadecimale (es. '4B') ne trova il corrispettivo valore decimale.'''

        symbol_dict={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,

                     '6':6,'7':7,'8':8,'9':9,

                     'A':10,'B':11,'C':12,'D':13,'E':14,'F':15}

        fst_hex = symbol_dict[value[0]]

        snd_hex = symbol_dict[value[1]]

        return (fst_hex*16 + snd_hex)

    def get_info_list(self):

        '''Questa funzione ritorna una lista delle informazioni sensibili.'''

        lst=[]

        info=""

        for el in self.get_ascii_list():

            if (el == "00"):

                lst.append(info)

                info=""

                continue

            else:

                info+=el

        return lst

if __name__ == "__main__":

    from id3parser import Id3Parser

    parser = Id3Parser()

    print parser.get_info_list()

COME SI USA:

Da shell:

$ hexdump -n 128 -v -e ‘1/1 “%02X” “\n”‘ <nome_file> | python id3parser.py

dove al posto di nome_file dovete mettere il titolo della canzone.

NOTA: Poichè il blog converte gli apici e i doppi apici in backquote, vi invito a riscrivervi tali apici se copiate ed incollate il codice nella shell, altrimenti non funziona (ringrazio Eugenio per la segnalazione).

Ci sono altri n-mila modi di farlo, mi interessava farlo così per farvi vedere come python sia un valido collante tra processi applicativi.

Vi allego come sempre il codice, alla prossima!

Alfredo Di Napoli

Codice: id3parser.py

2 thoughts on “PyPills – Lezione 2 – Stream, parsing and many more!

  1. Grazie mille !!!!!
    ha funzionato e inoltre funziona anche con altri formati di file non solo con gli mp3.
    piccola nota: dove descrivi l’opzione -e maca la chiusura del primo apice, io che sono poco esperto ci ho messo un’oretta a capire perchè non mi funzionava.

    Grazie del prezioso aiuto.
    Ciao
    Eugenio

  2. Caro Eugenio,
    sono felice ti abbia funzionato e ti abbia fatto capire quanto è
    potente Python.
    Rispondo alla tua nota facendoti notare che in realtà non è vero che manca la chiusura, la sintassi di -e è strana e prende delle stringhe in questo modo:
    -e ‘ “str1” “str2” ‘ (ho esagerato gli spazi)

    Il problema è che tu probabilmente avrai fatto copia ed incolla e putroppo il file così come è pubblicato dà problemi perchè il font su questo blog converte gli apici in backquote!
    Grazie della segnalazione però!
    Ciao!
    Alfredo

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...