2013-08-27 11 views
5

parte Interrogazione 1Python: re.compile e re.sub

ho ottenuto questo file f1:

<something @37> 
<name>George Washington</name> 
<a23c>Joe Taylor</a23c> 
</something @37> 

e voglio re.compile esso che assomiglia a questo f1: (con spazi)

George Washington Joe Taylor 

ho provato questo codice, ma si elimina un pò di tutto:

import re 
file = open('f1.txt') 
fixed = open('fnew.txt','w') 
text = file.read() 

match = re.compile('<.*>') 
for unwanted in text: 
    fixed_doc = match.sub(r' ',text) 

fixed.write(fixed_doc) 

La mia ipotesi è la riga re.compile ma non sono abbastanza sicuro di cosa farne. Non dovrei usare estensioni di terze parti. Qualche idea?


parte Interrogazione 2

avevo una domanda diversa sul confronto 2 file ho ottenuto questo codice da Alfe:

from collections import Counter 

def test(): 
    with open('f1.txt') as f: 
     contentsI = f.read() 
    with open('f2.txt') as f: 
     contentsO = f.read() 

    tokensI = Counter(value for value in contentsI.split() 
         if value not in []) 
    tokensO = Counter(value for value in contentsO.split() 
         if value not in []) 
    return not (tokensI - tokensO) and not (set(tokensO) - set(tokensI)) 

E 'possibile implementare il re.compile e re.sub nella sezione 'if value not in []'?

+0

Ciao. Nel primo problema, è tua intenzione eliminare TUTTI quelli che assomigliano a tag o tag che definiscono veramente un elemento di un linguaggio di markup? Uso la parola "elemento" nel suo giusto e corretto significato, ovvero "tag di inizio + contenuto di elementi + tag di fine". - Inoltre, man mano che esponi il contenuto del file f, ci sono delle righe, vale a dire delle newline. Quello che mostri come risultato desiderato è una stringa in cui non ci sono più righe nuove. E 'davvero quello che vuoi o ti piacerebbe mantenere la struttura in linea? – eyquem

+0

Cosa vorresti dire con '' se valore non in []) ''? Attualmente non ha senso, dal momento che non c'è sempre nulla in una lista di nulla. Cosa desideri fare come confronto dei file? Non è molto chiaro – eyquem

risposta

13

vi spiegherò cosa succede con il tuo codice:

import re 
file = open('f1.txt') 
fixed = open('fnew.txt','w') 
text = file.read() 

match = re.compile('<.*>') 
for unwanted in text: 
    fixed_doc = match.sub(r' ',text) 

fixed.write(fixed_doc) 

L'istruzione text = file.read() crea un oggetto di testo di tipo stringa nome text.
Nota che uso i caratteri in grassetto text per esprimere un OBJECT e text per esprimere il nome == IDENTIFIER di questo oggetto.
Come conseguenza dell'istruzione for unwanted in text:, l'identificatore unwanted viene successivamente assegnato a ciascun carattere a cui fa riferimento l'oggetto testo.

Inoltre, re.compile('<.*>') crea un oggetto di tipo RegexObject (che personnaly chiamo compilato) regex o semplicemente regex, <.*> essendo solo il pattern regex).
Assegnate questo oggetto regex compilato all'identificatore match: è una pessima pratica, perché match è già il nome di un metodo di oggetti regex in generale e di quello creato in particolare, quindi è possibile scrivere match.match senza errore.
match è anche il nome di una funzione del modulo re.
Questo uso di questo nome per il tuo particolare bisogno è molto confuso. Devi evitarlo.

C'è lo stesso difetto con l'uso di file come nome per il gestore di file del file f1. file è già un identificatore utilizzato nella lingua, è necessario evitarlo.

Bene. Ora questo partita oggetto cattivo nome è definito, l'istruzione fixed_doc = match.sub(r' ',text) sostituisce tutte le occorrenze si trovano in testo con la sostituzione r' ' dal regex partita.
Si noti che è completamente superfluo scrivere r' ' anziché solo ' ' perché non c'è assolutamente nulla in ' ' che deve essere sfuggito. È un maniaco di alcune persone ansiose scrivere stringhe non elaborate ogni volta che devono scrivere una stringa in un problema di regex.

A causa del suo modello <.+> in cui il simbolo del punto significa "avidamente mangiare ogni carattere situato tra un < e > tranne se si tratta di un carattere di nuova riga", le occorrenze catched nel testo da partita sono ogni linea fino a quando l'ultimo > in esso.
Poiché il nome unwanted non viene visualizzato in questa istruzione, è la stessa operazione eseguita per ciascun carattere del testo, uno dopo l'altro. Vale a dire: niente di interessante.
Per analizzare l'esecuzione di un programma, è necessario inserire alcune istruzioni di stampa nel codice, consentendo di capire cosa succede.Ad esempio, se fai print repr(fixed_doc), vedrai la stampa ripetuta di questo: ' \n \n \n '. Come ho detto: niente di interessante.

C'è un altro valore predefinito nel codice: si aprono i file, ma non li si chiude. È obbligatorio chiudere i file, altrimenti potrebbe accadere qualche strano fenomeno, che personalmente ho osservato in alcuni dei miei codici prima di rendermi conto di questo bisogno. Alcune persone fingono che non sia obbligatorio, ma è falso.
A proposito, il modo migliore per aprire e chiudere i file consiste nell'utilizzare l'istruzione with. Fa tutto il lavoro senza che tu ti debba preoccupare.

.

Così, ora posso proporre un codice per il primo problema:

import re 

def ripl(mat=None,li = []): 
    if mat==None: 
     li[:] = [] 
     return 
    if mat.group(1): 
     li.append(mat.span(2)) 
     return '' 
    elif mat.span() in li: 
     return '' 
    else: 
     return mat.group() 

r = re.compile('</[^>]+>' 
       '|' 
       '<([^>]+)>(?=.*?(</\\1>))', 
       re.DOTALL) 

text = '''<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37>''' 
print '1------------------------------------1' 
print text 
print '2------------------------------------2' 
ripl() 
print r.sub(ripl,text) 
print '3------------------------------------3' 

risultato

1------------------------------------1 
<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37> 
2------------------------------------2 

George <wxc>Washington 
Joe </zazaza>Taylor 

3------------------------------------3 

Il principio è il seguente:

Quando l'espressione regolare rileva un tag,
- se è un tag di chiusura, corrisponde a - se è un tag di inizio, corrisponde solo se c'è un tag di chiusura corrispondente da qualche parte ulteriormente nel testo
Per ciascuna corrispondenza, il metodo sub() della regex r chiama la funzione ripl() per eseguire la sostituzione.
Se la corrispondenza è con un tag di inizio (che è necessario seguito da qualche parte nel testo dal suo tag di chiusura corrispondente, per costruzione della regex), quindi ripl() restituisce ''.
Se la corrispondenza è con un tag di chiusura, ripl() restituisce '' solo se questo tag di fine è stato rilevato in precedenza nel testo è il tag di fine corrispondente di un tag di inizio precedente. Ciò è possibile effettuando la registrazione in un elenco li l'intervallo di span di ciascun tag finale corrispondente ogni volta che viene rilevato un tag di avvio e corrispondente.

La lista di registrazione li è definito come un argomento di default in modo che sia sempre la stessa lista che viene utilizzato a ogni chiamata della funzione ripl() (si prega, si riferiscono alla functionning di argomento di default per undertsand, perché è sottile).
Come conseguenza della definizione di li come parametro che riceve un argomento predefinito, l'oggetto elenco li conserva tutti gli span registrati durante l'analisi di più testo nel caso in cui più testi vengano analizzati successivamente. Per evitare che l'elenco li conservi gli span delle corrispondenze di testo passate, è necessario rendere l'elenco vuoto. Ho scritto la funzione in modo che il primo parametro sia definito con un argomento predefinito None: che consente di chiamare ripl() senza argomento prima di utilizzarlo nel metodo sub() di un'ergere.
Quindi, si deve pensare di scrivere ripl() prima di utilizzarlo.

.

Se si desidera rimuovere i ritorni a capo del testo al fine di ottenere il risultato preciso hai mostrato nella sua interrogazione, il codice deve essere modificato per:

import re 

def ripl(mat=None,li = []): 
    if mat==None: 
     li[:] = [] 
     return 
    if mat.group(1): 
     return '' 
    elif mat.group(2): 
     li.append(mat.span(3)) 
     return '' 
    elif mat.span() in li: 
     return '' 
    else: 
     return mat.group() 


r = re.compile('(*\n *)' 
       '|' 
       '</[^>]+>' 
       '|' 
       '<([^>]+)>(?=.*?(</\\2>)) *', 
       re.DOTALL) 

text = '''<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37>''' 
print '1------------------------------------1' 
print text 
print '2------------------------------------2' 
ripl() 
print r.sub(ripl,text) 
print '3------------------------------------3' 

risultato

1------------------------------------1 
<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37> 
2------------------------------------2 
George <wxc>WashingtonJoe </zazaza>Taylor 
3------------------------------------3 
+0

@Duboe Per favore, vedi la mia risposta. Si noti che il carattere sostitutivo che ho usato in esso è '' '' '', non un vuoto '' '' '' ' – eyquem

1

È possibile utilizzare Beautiful Soup di farlo facilmente:

from bs4 import BeautifulSoup 
file = open('f1.txt') 
fixed = open('fnew.txt','w') 

#now for some soup 

soup = BeautifulSoup(file) 

fixed.write(str(soup.get_text()).replace('\n',' ')) 

L'uscita della linea di cui sopra saranno:

George Washington Joe Taylor 

(Atleast questo funziona con il campione che mi hai dato)

Scusa non capisco la parte 2, buona fortuna!

+0

Questo è abbastanza bello anche se non sono in grado di usare estensioni che non sono già incluse:/ma potrei usarlo per alcuni progetti futuri :) – dustinboettcher

0

In base alla prima parte, mancava "?"

match = re.compile('<.*?>') 

fa il trucco.


In ogni caso, non sono ancora sicuro delle seconde domande. :/

+0

È una soluzione troppo semplice. Ad esempio con '' text = 'Atlantic <--- questo è un oceano. << >> \ nBat <--- questo è un animale * rimuovilo * ''' il risultato di '' re.sub (' <.+?> ',' ', testo) '' è ''' Atlantic >> \ nBat < --- questo è un animale * rimuovilo * '''. È per evitare tali casi che ho scritto il codice nella mia risposta – eyquem

0

Per la parte 1 provare il seguente frammento di codice. Tuttavia considerare l'utilizzo di una libreria come BeautifulSoup come suggerito da Moe Jan

import re 
import os 
def main(): 
    f = open('sample_file.txt') 
    fixed = open('fnew.txt','w') 



    #pattern = re.compile(r'(?P<start_tag>\<.+?\>)(?P<content>.*?)(?P<end_tag>\</.+?\>)') 
    pattern = re.compile(r'(?P<start><.+?>)(?P<content>.*?)(</.+?>)') 
    output_text = [] 
    for text in f: 
     match = pattern.match(text) 
     if match is not None: 
      output_text.append(match.group('content')) 

    fixed_content = ' '.join(output_text) 


    fixed.write(fixed_content) 
    f.close() 
    fixed.close() 

if __name__ == '__main__': 
    main() 

Da parte 2:

io non sono del tutto chiaro con quello che stai chiedendo - tuttavia la mia ipotesi è che si vuole fare qualcosa come if re.sub(value) not in []. Tuttavia, si noti che è necessario chiamare re.compile solo una volta prima di inizializzare l'istanza Counter. Sarebbe meglio se chiarissi la seconda parte della tua domanda.

In realtà, ti consiglio di utilizzare il modulo diff in Python integrato per trovare la differenza tra due file.Usando questo modo meglio di usare il proprio algoritmo di diff, dal momento che la logica di diff è ben testata e ampiamente utilizzata e non è vulnerabile agli errori logici o programmatici derivanti dalla presenza di newline spuri, caratteri di tab e spazio.