2010-04-07 26 views
9

Tôi đang cố gắng để chạy subprocess.call() với unicode filename, và đây được đơn giản hóa:Unicode filename để trăn subprocess.call()

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

subprocess.call(n + f) 

điều này làm tăng lỗi nổi tiếng:

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

Mã hóa thành utf-8 tạo tên tệp sai và mbcs chuyển tên tệp là new.txt mà không có dấu

Tôi không thể đọc thêm về chủ đề khó hiểu này và quay vòng tròn. Tôi tìm thấy ở đây rất nhiều câu trả lời cho nhiều vấn đề khác nhau trong quá khứ vì vậy tôi nghĩ để tham gia và yêu cầu giúp đỡ bản thân mình

Cảm ơn

+0

Tùy thuộc vào hệ điều hành của bạn, điều gì sẽ xảy ra nếu bạn sử dụng mã latin-1 hoặc cp1252 làm mã hóa của mình? –

+1

Bạn đã chỉ định mã hóa của tệp nguồn chưa? –

+0

tệp nguồn được mã hóa utf: # - * - mã hóa: utf-8 - * - Tôi sử dụng mẹo với latin-1 theo thời gian nhưng không thể trong trường hợp này: 1. Tôi cũng cần các ký tự khác không có trong latin-1 2. Thật không may nó không hoạt động với subprocess - cùng một lỗi được nêu ra, tôi đã mã hóa cả hai chuỗi với cùng mã hóa latin-1 Cảm ơn mọi câu trả lời – otrov

Trả lời

0

Tôi không có một câu trả lời cho bạn, nhưng tôi đã làm được một số tiền hợp lý của nghiên cứu vấn đề này. Python chuyển đổi tất cả đầu ra (bao gồm cả các cuộc gọi hệ thống) sang cùng một ký tự như thiết bị đầu cuối mà nó đang chạy. Các thiết bị đầu cuối Windows sử dụng các trang mã để lập bản đồ ký tự; trang mã mặc định là 437, nhưng nó có thể được thay đổi bằng lệnh chcp. chcp 65001 về mặt lý thuyết sẽ thay đổi trang mã thành utf-8, nhưng theo như tôi biết python không biết phải làm gì với điều này, vì vậy bạn SOL.

1

Dường như để thực hiện công việc này, mã xử lý con sẽ phải được sửa đổi để sử dụng phiên bản ký tự rộng của CreateProcess (giả định rằng phiên bản đó tồn tại). Có một PEP thảo luận về sự thay đổi tương tự đối với đối tượng tệp tại http://www.python.org/dev/peps/pep-0277/ Có lẽ bạn có thể nghiên cứu các cuộc gọi Windows C và đề xuất một thay đổi tương tự cho tiến trình con.

+0

I không cảm thấy đến nhiệm vụ nghiên cứu vấn đề này, bạn vui khi thấy tác giả (Neil), người vừa phát hành SciTE 2.10 với hỗ trợ truy cập tên unicode (rộng char) – otrov

0

Bạn có thể thử mở các tập tin như:

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

hoặc bất cứ bảng mã chcp báo cáo như được sử dụng trong một cửa sổ command prompt. Nếu bạn cố gắng chcp 65001 như được đề xuất starbuck, bạn sẽ phải chỉnh sửa bảng mã stdlib \ aliases.py và thêm cp65001 làm bí danh cho 'utf-8' trước. Đó là một vấn đề mở trong nguồn Python.

CẬP NHẬT: vì đây là kịch bản nhiều mục tiêu, trước khi chạy lệnh như vậy, hãy đảm bảo bạn chạy một lệnh chcp trước tiên, phân tích đầu ra và truy xuất mã "Command Prompt" (DOS) hiện tại. Sau đó, sử dụng trang mã được phát hiện để mã hóa đối số subprocess.call.

+0

Tôi đang dùng cp1251, nhưng chương trình là được cho là chạy trên các máy khác nhau với miền địa phương tùy ý – otrov

+0

cp1251 là trang mã Windows. Khi chạy các lệnh với tiến trình con, bạn cần sử dụng mã lệnh "DOS"/dấu nhắc lệnh. – tzot

+0

@tzot: không đúng trừ khi bạn có nghĩa là mã hóa 'mbcs' (bạn có thể thấy giá trị của nó bằng' locale.getpreferredencoding() ') và OP đã nói rằng' mbcs' trên hệ thống của anh ta không hỗ trợ các ký tự được yêu cầu.'chcp' có thể trả về mã hóa khác nhau. – jfs

0

Vì ΤΖΩΤΖΙΟΥ và starbuck được đề cập, vấn đề là với trang mã bảng điều khiển nằm trong trường hợp của bạn 866 (trong bản địa hóa tiếng Nga của cửa sổ) và không phải 1251. Chỉ cần chạy chcp trong bảng điều khiển.

Sự cố cũng giống như khi bạn muốn xuất unicode sang giao diện điều khiển Windows. Unfortunatelly bạn sẽ cần ít nhất để reqister và bí danh cho unicode như 'cp866' trong encodings \ aliases.py (hoặc làm điều đó lập trình trên script bắt đầu) và thay đổi trang mã của bàn điều khiển để 65001 trước khi chạy notepad và thiết lập nó trở lại sau đó .

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

Bằng cách này, để có thể chạy các lệnh trong giao diện điều khiển và xem tên tập tin một cách chính xác, bạn sẽ cần phải thay đổi font giao diện điều khiển để Lucida Console trong thuộc tính giao diện điều khiển cửa sổ.

Thậm chí có thể còn tồi tệ hơn: bạn cần phải thay đổi trang mã của quy trình hiện tại. Để làm điều đó, bạn sẽ cần chạy chcp 65001 ngay trước khi tập lệnh bắt đầu hoặc sử dụng pywin32 để thực hiện nó trong tập lệnh.

+0

Cảm ơn tất cả những người đã nỗ lực, được đánh giá cao :) Thật không may tôi không thể làm cho nó hoạt động. Chuỗi được truyền đến subprocess(), hoặc chính xác hơn CreateProcess() được in dưới dạng "chcp 65001 & c: \ windows \ notepad.exe nèw.txt" mà ném lỗi "hệ thống không thể tìm thấy tệp được chỉ định". Có lẽ tôi đang làm sai, nhưng tôi đã thử những gì tôi hiểu Tôi không có vấn đề dán unicode tên tập tin trong cửa sổ giao diện điều khiển trong cp hiện tại của tôi, có thể được nhìn thấy ở đây: http://img402.imageshack.us/img402/ 9875/sshot1x.png – otrov

6

Nếu tệp của bạn tồn tại, bạn có thể sử dụng short filename (còn gọi là 8,3 tên). Tên này được xác định đối với các tệp hiện có và sẽ không gây ra sự cố nào đối với các chương trình nhận biết không phải Unicode khi được chuyển làm đối số.

Một cách để có được một (cần Pywin32 phải được cài đặt):

import win32api 
short_path = win32api.GetShortPathName(unicode_path) 

Ngoài ra, bạn cũng có thể sử dụng 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, điều đó hoàn toàn kinh tởm! tiện dụng mặc dù. – jambox

0

Sử dụng os.startfile với chỉnh sửa hoạt động. Điều này sẽ hoạt động tốt hơn vì nó sẽ mở ứng dụng mặc định cho tiện ích mở rộng của bạn.

6

Tôi đã tìm được giải pháp tốt, hơi lộn xộn, nhưng nó hoạt động.

subprocess.call sẽ chuyển văn bản trong mã hóa riêng của nó tới thiết bị đầu cuối, có thể hoặc không phải là mã đang chờ. Bởi vì bạn muốn làm cho nó di động, bạn sẽ cần phải biết mã hóa của máy khi chạy.

Sau đây

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

nỗ lực để tìm ra các mã hóa hiện tại và do đó áp dụng điều đúng để subprocess.call

Là một sidenote, tôi cũng đã tìm thấy rằng nếu bạn cố gắng để soạn một chuỗi với thư mục hiện tại, sử dụng

os.cwd() 

Python (hoặc hệ điều hành, không biết) sẽ làm lộn xộn các thư mục có ký tự có dấu. Để ngăn chặn điều này, tôi đã tìm thấy những điều sau đây để hoạt động:

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

Điều này rất giống với giải pháp ở trên.

Hy vọng điều đó sẽ hữu ích.

+0

OP nói: * "mbcs chuyển tên tệp thành new.txt mà không có dấu" *. 'mbcs' là' sys.getfilesystemencoding() 'trên Windows, tức là' .encode (sys.getfilesystemencoding()) 'không hoạt động trong trường hợp này. – jfs

+0

@ J.F.Sebastian, chúng tôi không thấy cùng OP;) Tệp 'nèw.txt' có dấu trọng âm. – Kpym

+0

@Kpym: đó là trích dẫn trực tiếp từ câu hỏi có nghĩa là mã hóa tên Unicode có dấu ('nèw.txt') bằng cách sử dụng mã ANSI của Windows (' mbcs') có thể và không bị mất dấu trên hệ thống của OP, ví dụ: 'u 'nèw.txt'.encode (' ascii ',' ignore ') '->' b'new.txt'' (mã thực tế không phải là ascii) – jfs