2010-04-07 4 views
9

Sto cercando di eseguire subprocess.call() con il nome del file unicode, e qui è semplificata:Unicode nome del file da python subprocess.call()

n = u'c:\\windows\\notepad.exe ' 
f = u'c:\\temp\\nèw.txt' 

subprocess.call(n + f) 

che solleva famoso errore:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe8'

La codifica per utf-8 produce un nome file errato e mbcs passa il nome file come new.txt senza accento

Non riesco proprio a leggere su questo argomento confuso e girare in cerchio. Ho trovato qui molte risposte per molti problemi diversi in passato, così ho pensato di unirsi e chiedere aiuto me

Grazie

+0

A seconda del sistema operativo in uso, cosa succede se si utilizza latin-1 o cp1252 come codifica? –

+1

Hai specificato la codifica del file sorgente? –

+0

il codice sorgente è codificato utf: # - * - codifica: utf-8 - * - Io uso il trucco con Latino-1 di volta in volta ma non posso in questo caso: 1. Ho bisogno anche di altri caratteri che non sono in latino-1 2. Sfortunatamente non funziona con sottoprocesso - lo stesso errore è stato sollevato, tu ho codificato entrambe le stringhe con la stessa codifica latin-1 Grazie per tutte le risposte – otrov

risposta

0

Non ho una risposta per voi, ma ho fatto una discreta quantità di ricerca su questo problema. Python converte tutti gli output (incluse le chiamate di sistema) nello stesso carattere del terminale in cui è in esecuzione. I terminali di Windows usano le code page per la mappatura dei caratteri; la tabella codici predefinita è 437, ma può essere modificata con il comando chcp. chcp 65001 teoricamente cambierà la tabella codici in utf-8, ma per quanto ne so python non sa cosa fare con questo, quindi tu sei SOL.

1

Sembra che per eseguire questa operazione, il codice di sottoprocesso dovrebbe essere modificato per utilizzare una versione a caratteri larghi di CreateProcess (presupponendo che ne esiste uno). C'è un PEP che discute la stessa modifica apportata per l'oggetto file a http://www.python.org/dev/peps/pep-0277/ Forse potresti cercare le chiamate di Windows C e proporre una modifica simile per il sottoprocesso.

+0

I non ti senti all'altezza del compito di ricercare in questo problema, sei curioso di vedere l'autore (Neil), che ha appena rilasciato SciTE 2.10 con supporto per l'accesso al nome file unicode (wide char) – otrov

0

Si può provare ad aprire il file come:

subprocess.call((n + f).encode("cp437")) 

o qualsiasi tabella codici chcp rapporti come viene utilizzato in una finestra del prompt dei comandi. Se provi a chcp 65001 come suggerito da starbuck, dovrai modificare il file codifica \ aliases.py di stdlib e aggiungere cp65001 come un alias a "utf-8" in anticipo. È un problema aperto nel sorgente Python.

AGGIORNAMENTO: poiché si tratta di uno scenario a più destinazioni, prima di eseguire tale comando, assicurarsi di eseguire prima un singolo comando chcp, analizzare l'output e recuperare la codepage "Prompt dei comandi" (DOS) corrente. Successivamente, utilizzare la codepage rilevata per codificare l'argomento subprocess.call.

+0

Sono su cp1251, ma il programma è supposto per funzionare su macchine diverse con locale arbitrario – otrov

+0

cp1251 è la tabella codici di Windows. Quando si eseguono i comandi con sottoprocesso, è necessario utilizzare la codepage "DOS"/prompt dei comandi. – tzot

+0

@tzot: non è corretto a meno che non si intenda la codifica 'mbcs' (si potrebbe vedere il suo valore usando' locale.getpreferredencoding() ') e OP ha già detto che' mbcs' sul suo sistema non supporta i caratteri richiesti.'chcp' può restituire una codifica diversa. – jfs

0

Come ΤΖΩΤΖΙΟΥ e starbuck menzionato, il problema è con la pagina di codice della console che è nel tuo caso 866 (nella localizzazione russa di Windows) e non nel 1251. Basta eseguire chcp nella console.

Il problema è lo stesso di quando si desidera eseguire l'output unicode sulla console di Windows. Purtroppo sarà necessario almeno reqister e alias per unicode come 'cp866' in encodings \ aliases.py (o farlo a livello di codice all'avvio dello script) e cambiare la code page della console in 65001 prima di eseguire il blocco note e reimpostarlo in seguito .

chcp 65001 & c:\WINDOWS\notepad.exe nèw.txt & chcp 866 

Tra l'altro, per essere in grado di eseguire il comando in console e vedere il nome del file in modo corretto, è necessario modificare il carattere della console a Lucida Console nelle proprietà finestra della console.

Potrebbe anche essere peggio: sarà necessario modificare la tabella codici del processo corrente. Per fare ciò, è necessario eseguire chcp 65001 subito prima dell'avvio dello script o utilizzare pywin32 per farlo all'interno dello script.

+0

Grazie per tutti gli sforzi ragazzi, molto apprezzato :) Purtroppo non riesco a farlo funzionare. La stringa passata al sottoprocesso() o più precisamente CreateProcess() viene stampata come "chcp 65001 & c: \ windows \ notepad.exe nèw.txt" che genera l'errore "il sistema non riesce a trovare il file specificato". Forse lo sto facendo male, ma ho provato quello che ho capito Non ho problemi ad incollare il nome file unicode in windows console nel mio attuale cp, che può essere visto qui: http://img402.imageshack.us/img402/ 9875/sshot1x.png – otrov

6

Se il file esiste, è possibile utilizzare short filename (alias nome 8.3). Questo nome è definito per i file esistenti e non dovrebbe causare problemi ai programmi non Unicode quando vengono passati come argomento.

Un modo per ottenere uno (ha bisogno Pywin32 per essere installato):

import win32api 
short_path = win32api.GetShortPathName(unicode_path) 

In alternativa, è anche possibile utilizzare ctypes:

import ctypes 
import ctypes.wintypes 

ctypes.windll.kernel32.GetShortPathNameW.argtypes = [ 
    ctypes.wintypes.LPCWSTR, # lpszLongPath 
    ctypes.wintypes.LPWSTR, # lpszShortPath 
    ctypes.wintypes.DWORD # cchBuffer 
] 
ctypes.windll.kernel32.GetShortPathNameW.restype = ctypes.wintypes.DWORD 

buf = ctypes.create_unicode_buffer(1024) # adjust buffer size, if necessary 
ctypes.windll.kernel32.GetShortPathNameW(unicode_path, buf, len(buf)) 

short_path = buf.value 
+2

hehe, è assolutamente disgustoso! a portata di mano però. – jambox

0

Utilizzare os.startfile con la modifica il funzionamento. Funzionerà meglio poiché aprirà l'applicazione predefinita per la tua estensione.

6

Ho trovato una soluzione eccellente, è un po 'caotico, ma funziona.

subprocess.call sta per passare il testo nella propria codifica al terminale, che potrebbe essere o non essere quello che si aspetta. Perché vuoi renderlo portabile, dovrai conoscere la codifica della macchina in fase di runtime.

Il seguente

notepad = 'C://Notepad.exe' 
subprocess.call([notepad.encode(sys.getfilesystemencoding())]) 

tentativi per capire la codifica corrente e applica quindi uno corretto subprocess.call

Come sidenote, ho trovato che anche se si tenta di comporre una stringa con la directory corrente, usando

os.cwd() 

Python (o il sistema operativo, non so) rovinerà le directory con caratteri accentati. Per evitare questo ho trovato il seguente a lavorare:

os.cwd().decode(sys.getfilesystemencoding()) 

Che è molto simile alla soluzione di cui sopra.

Spero che aiuti.

+0

OP dice: * "mbcs passa il nome del file come new.txt senza accento" *. 'mbcs' è' sys.getfilesystemencoding() 'su Windows i.e.,' ​​.encode (sys.getfilesystemencoding()) 'non funziona in questo caso. – jfs

+0

@ J.F.Sebastian non vediamo lo stesso OP;) Il file 'nèw.txt' è con accenti. – Kpym

+0

@Kpym: è una citazione diretta dalla domanda che significa che codificare un nome Unicode con accento ('nèw.txt') usando la codepage ANSI di Windows (' mbcs') può e perde l'accento sul sistema OP, ad es. 'nèw.txt'.encode (' ascii ',' ignore ') '->' b'new.txt'' (la codepage effettiva non è ascii) – jfs