Lettura di caratteri da file in Python


102

In un file di testo, c'è una stringa "Non mi piace".

Tuttavia, quando lo leggo in una stringa, diventa "Non \ xe2 \ x80 \ x98t in questo modo". Capisco che \ u2018 sia la rappresentazione Unicode di "'". Io uso

f1 = open (file1, "r")
text = f1.read()

comando per eseguire la lettura.

Ora, è possibile leggere la stringa in modo tale che quando viene letta nella stringa, sia "Non mi piace", invece di "Non \ xe2 \ x80 \ x98t in questo modo"?

Seconda modifica: ho visto alcune persone usare la mappatura per risolvere questo problema, ma davvero, non esiste una conversione incorporata che esegua questo tipo di conversione da ANSI a unicode (e viceversa)?


Alcuni commenti: ho visto alcune persone usare la mappatura per risolvere questo problema, ma davvero, non esiste una conversione incorporata che esegua questo tipo di conversione da ANSI a unicode (e viceversa)? Grazie!
Graviton

Non c'è, perché ci sono centinaia di migliaia di punti di codice Unicode. Come decidereste quale dovrebbe essere mappato a quali caratteri ASCII?
John Millikin,

2
btw, il tuo file di testo è rotto! U + 2018 è il "SEGNO DI CITAZIONE SINGOLA SINISTRA", non un apostrofo (U + 0027 più comunemente).

john, il tuo commento è sbagliato, almeno in senso generale. iconv lib può essere usato per traslitterare caratteri Unicode in ascii (anche dipendente dalla localizzazione. $ python -c 'print u "\ u2018" .encode ("utf-8")' | iconv -t 'ascii // translit' | xxd 0000000: 270a

il fatto è che devi convertire UNICODE in ASCII (non il contrario).
hasen

Risposte:


157

Rif: http://docs.python.org/howto/unicode

Leggere Unicode da un file è quindi semplice:

import codecs
with codecs.open('unicode.rst', encoding='utf-8') as f:
    for line in f:
        print repr(line)

È anche possibile aprire i file in modalità di aggiornamento, consentendo sia la lettura che la scrittura:

with codecs.open('test', encoding='utf-8', mode='w+') as f:
    f.write(u'\u4500 blah blah blah\n')
    f.seek(0)
    print repr(f.readline()[:1])

EDIT : presumo che l'obiettivo previsto sia solo quello di essere in grado di leggere correttamente il file in una stringa in Python. Se stai tentando di convertire in una stringa ASCII da Unicode, non esiste davvero un modo diretto per farlo, poiché i caratteri Unicode non esisteranno necessariamente in ASCII.

Se stai tentando di convertire in una stringa ASCII, prova uno dei seguenti:

  1. Sostituisci i caratteri Unicode specifici con equivalenti ASCII, se stai solo cercando di gestire alcuni casi speciali come questo particolare esempio

  2. Usa il unicodedatamodulo normalize()e il string.encode()metodo per convertire nel miglior modo possibile al prossimo equivalente ASCII più vicino (Ref https://web.archive.org/web/20090228203858/http://techxplorer.com/2006/07/18/converting- unicode-to-ascii-using-python ):

    >>> teststr
    u'I don\xe2\x80\x98t like this'
    >>> unicodedata.normalize('NFKD', teststr).encode('ascii', 'ignore')
    'I donat like this'
    

3
codecsil modulo non gestisce correttamente la modalità di ritorno a capo universale. Utilizzare io.open()invece su Python 2.7+ (è integrato open()in Python 3).
jfs

15

Ci sono alcuni punti da considerare.

Un carattere \ u2018 può apparire solo come un frammento di rappresentazione di una stringa Unicode in Python, ad esempio se scrivi:

>>> text = u'‘'
>>> print repr(text)
u'\u2018'

Ora, se vuoi semplicemente stampare la stringa unicode in modo carino, usa il encodemetodo unicode :

>>> text = u'I don\u2018t like this'
>>> print text.encode('utf-8')
I dont like this

Per assicurarti che ogni riga di qualsiasi file venga letta come unicode, faresti meglio a usare la codecs.openfunzione anziché solo open, che ti consente di specificare la codifica del file:

>>> import codecs
>>> f1 = codecs.open(file1, "r", "utf-8")
>>> text = f1.read()
>>> print type(text)
<type 'unicode'>
>>> print text.encode('utf-8')
I dont like this

6

Ma in realtà è "Non mi piace" e non "Non mi piace". Il carattere u '\ u2018' è un carattere completamente diverso da "'" (e, visivamente, dovrebbe corrispondere più a' `').

Se stai cercando di convertire l'unicode codificato in ASCII semplice, potresti forse mantenere una mappatura della punteggiatura unicode che vorresti tradurre in ASCII.

punctuation = {
  u'\u2018': "'",
  u'\u2019': "'",
}
for src, dest in punctuation.iteritems():
  text = text.replace(src, dest)

Ci sono un sacco di caratteri di punteggiatura in Unicode , tuttavia, ma suppongo che tu possa contare su solo alcuni di essi effettivamente utilizzati da qualsiasi applicazione stia creando i documenti che stai leggendo.


1
in realtà, se fai in modo che il dict associ gli ordinali Unicode agli ordinali Unicode ({0x2018: 0x27, 0x2019: 0x27}) puoi semplicemente passare l'intero dict a text.translate () per eseguire tutte le sostituzioni in una volta.
Thomas Wouters

5

È anche possibile leggere un file di testo codificato utilizzando il metodo di lettura di python 3:

f = open (file.txt, 'r', encoding='utf-8')
text = f.read()
f.close()

Con questa variazione, non è necessario importare alcuna libreria aggiuntiva


3

Lasciando da parte il fatto che il tuo file di testo è rotto (U + 2018 è una virgoletta sinistra, non un apostrofo): iconv può essere usato per traslitterare caratteri Unicode in ASCII.

Dovrai cercare "iconvcodec" su Google, poiché il modulo sembra non essere più supportato e non riesco a trovare una home page canonica per esso.

>>> import iconvcodec
>>> from locale import setlocale, LC_ALL
>>> setlocale(LC_ALL, '')
>>> u'\u2018'.encode('ascii//translit')
"'"

In alternativa puoi utilizzare l' iconvutilità della riga di comando per ripulire il tuo file:

$ xxd foo
0000000: e280 980a                                ....
$ iconv -t 'ascii//translit' foo | xxd
0000000: 270a                                     '.

2

C'è la possibilità che in qualche modo tu abbia una stringa non Unicode con caratteri di escape Unicode, ad esempio:

>>> print repr(text)
'I don\\u2018t like this'

In realtà mi è già successo una volta. Puoi utilizzare un unicode_escapecodec per decodificare la stringa in unicode e quindi codificarla in qualsiasi formato desideri:

>>> uni = text.decode('unicode_escape')
>>> print type(uni)
<type 'unicode'>
>>> print uni.encode('utf-8')
I dont like this

1

Questo è il modo in cui Pythons ti mostra le stringhe con codifica Unicode. Ma penso che dovresti essere in grado di stampare la stringa sullo schermo o scriverla in un nuovo file senza problemi.

>>> test = u"I don\u2018t like this"
>>> test
u'I don\u2018t like this'
>>> print test
I dont like this

1

In realtà, U + 2018 è la rappresentazione Unicode del carattere speciale '. Se lo desideri, puoi convertire le istanze di quel carattere in U + 0027 con questo codice:

text = text.replace (u"\u2018", "'")

Inoltre, cosa stai usando per scrivere il file? f1.read()dovrebbe restituire una stringa simile a questa:

'I don\xe2\x80\x98t like this'

Se restituisce questa stringa, il file viene scritto in modo errato:

'I don\u2018t like this'

Scusa! Come hai detto, ritorna "Non \ xe2 \ x80 \ x98t in questo modo"
Graviton,

Il messaggio 'Non \ xe2 \ x80 \ x98t come questo' che stai vedendo è ciò che Python chiamerebbe str. Sembra essere la codifica utf-8 di u'I don \ u2018t like this ', che è un'istanza Unicode in Python. Prova a chiamare .decode ('utf-8') nel primo o .encode ('utf-8') nel secondo.
Logan

@hop: oops, forgot ord () restituisce decimal invece di hex. Grazie per la cattura.
John Millikin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.