اقرأ أحرف Unicode من وسيطات سطر الأوامر في Python 2.x على نظام التشغيل Windows
-
21-08-2019 - |
سؤال
أريد أن يكون برنامج Python النصي الخاص بي قادرًا على قراءة وسيطات سطر أوامر Unicode في Windows.ولكن يبدو أن sys.argv عبارة عن سلسلة مشفرة باستخدام بعض الترميز المحلي، وليس Unicode.كيف يمكنني قراءة سطر الأوامر في Unicode بالكامل؟
رمز المثال: argv.py
import sys
first_arg = sys.argv[1]
print first_arg
print type(first_arg)
print first_arg.encode("hex")
print open(first_arg)
على جهاز الكمبيوتر الخاص بي الذي تم إعداده لصفحة الرموز اليابانية، أحصل على:
C:\temp>argv.py "PC・ソフト申請書08.09.24.doc"
PC・ソフト申請書08.09.24.doc
<type 'str'>
50438145835c83748367905c90bf8f9130382e30392e32342e646f63
<open file 'PC・ソフト申請書08.09.24.doc', mode 'r' at 0x00917D90>
أعتقد أن هذا هو Shift-JIS المشفر، وهو "يعمل" مع اسم الملف هذا.ولكنه ينقطع عن أسماء الملفات التي تحتوي على أحرف غير موجودة في مجموعة أحرف Shift-JIS - يفشل استدعاء "الفتح" الأخير:
C:\temp>argv.py Jörgen.txt
Jorgen.txt
<type 'str'>
4a6f7267656e2e747874
Traceback (most recent call last):
File "C:\temp\argv.py", line 7,
in <module>
print open(first_arg)
IOError: [Errno 2] No such file or directory: 'Jorgen.txt'
ملحوظة: أنا أتحدث عن Python 2.x، وليس Python 3.0.لقد وجدت أن Python 3.0 يعطي sys.argv
كما Unicode السليم.لكن ما زال الوقت مبكرًا بعض الشيء للانتقال إلى Python 3.0 (بسبب نقص دعم مكتبة الطرف الثالث).
تحديث:
قالت بعض الإجابات إنه يجب علي فك التشفير وفقًا لأي شيء sys.argv
تم ترميزه في.المشكلة في ذلك هي أنها ليست Unicode كاملة، لذا لا يمكن تمثيل بعض الأحرف.
إليك حالة الاستخدام التي تسبب لي الحزن:أملك تمكين سحب وإسقاط الملفات على ملفات .py في مستكشف Windows.لدي أسماء ملفات تحتوي على جميع أنواع الأحرف، بما في ذلك بعضها غير موجود في صفحة الرموز الافتراضية للنظام.لا يحصل برنامج Python النصي الخاص بي على أسماء ملفات Unicode الصحيحة التي تم تمريرها إليه عبر sys.argv في جميع الحالات، عندما لا تكون الأحرف قابلة للتمثيل في تشفير صفحة الرموز الحالية.
من المؤكد أن هناك بعض واجهات برمجة تطبيقات Windows لقراءة سطر الأوامر باستخدام Unicode الكامل (وPython 3.0 يفعل ذلك).أفترض أن مترجم Python 2.x لا يستخدمه.
المحلول
إليك الحل الذي أبحث عنه تمامًا، وهو إجراء مكالمة إلى Windows GetCommandLineArgvW
وظيفة:
احصل على sys.argv بأحرف Unicode ضمن Windows (من اكتيف ستيت)
لكنني قمت بإجراء العديد من التغييرات لتبسيط استخدامه والتعامل بشكل أفضل مع استخدامات معينة.وهنا ما أستخدمه:
win32_unicode_argv.py
"""
win32_unicode_argv.py
Importing this will replace sys.argv with a full Unicode form.
Windows only.
From this site, with adaptations:
http://code.activestate.com/recipes/572200/
Usage: simply import this module into a script. sys.argv is changed to
be a list of Unicode strings.
"""
import sys
def win32_unicode_argv():
"""Uses shell32.GetCommandLineArgvW to get sys.argv as a list of Unicode
strings.
Versions 2.x of Python don't support Unicode in sys.argv on
Windows, with the underlying Windows API instead replacing multi-byte
characters with '?'.
"""
from ctypes import POINTER, byref, cdll, c_int, windll
from ctypes.wintypes import LPCWSTR, LPWSTR
GetCommandLineW = cdll.kernel32.GetCommandLineW
GetCommandLineW.argtypes = []
GetCommandLineW.restype = LPCWSTR
CommandLineToArgvW = windll.shell32.CommandLineToArgvW
CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)]
CommandLineToArgvW.restype = POINTER(LPWSTR)
cmd = GetCommandLineW()
argc = c_int(0)
argv = CommandLineToArgvW(cmd, byref(argc))
if argc.value > 0:
# Remove Python executable and commands if present
start = argc.value - len(sys.argv)
return [argv[i] for i in
xrange(start, argc.value)]
sys.argv = win32_unicode_argv()
الآن، الطريقة التي أستخدمها بها هي ببساطة القيام بما يلي:
import sys
import win32_unicode_argv
ومنذ ذلك الحين، sys.argv
هي قائمة سلاسل Unicode.بايثون optparse
يبدو أن الوحدة سعيدة بتحليلها، وهو أمر رائع.
نصائح أخرى
التعامل مع الترميزات مربك للغاية.
أنا يعتقد إذا قمت بإدخال البيانات عبر سطر الأوامر، فسيتم تشفير البيانات مهما كان ترميز نظامك وليس Unicode.(حتى النسخ/اللصق يجب أن يفعل ذلك)
لذلك يجب أن يكون من الصحيح فك التشفير إلى Unicode باستخدام تشفير النظام:
import sys
first_arg = sys.argv[1]
print first_arg
print type(first_arg)
first_arg_unicode = first_arg.decode(sys.getfilesystemencoding())
print first_arg_unicode
print type(first_arg_unicode)
f = codecs.open(first_arg_unicode, 'r', 'utf-8')
unicode_text = f.read()
print type(unicode_text)
print unicode_text.encode(sys.getfilesystemencoding())
تشغيل ما يلي سوف الإخراج:موجه> python myargv.py "PC・ソフト申請書08.09.24.txt"
PC・ソフト申請書08.09.24.txt
<type 'str'>
<type 'unicode'>
PC・ソフト申請書08.09.24.txt
<type 'unicode'>
?日本語
حيث يحتوي ملف "PC・ソフト申請書08.09.24.txt" على النص "日本語".(لقد قمت بتشفير الملف كـ utf8 باستخدام Windows Notepad، وأنا في حيرة من أمري بشأن سبب وجود "؟" في البداية عند الطباعة.هل هناك علاقة بكيفية قيام المفكرة بحفظ utf8؟)
يمكن استخدام طريقة "فك تشفير" السلاسل أو unicode() المضمنة لتحويل ترميز إلى Unicode.
unicode_str = utf8_str.decode('utf8')
unicode_str = unicode(utf8_str, 'utf8')
أيضًا، إذا كنت تتعامل مع الملفات المشفرة، فقد ترغب في استخدام وظيفة codecs.open() بدلاً من وظيفة open() المضمنة.فهو يسمح لك بتحديد تشفير الملف، وبعد ذلك سيتم استخدام التشفير المحدد لفك تشفير المحتوى بشفافية إلى Unicode.
لذلك عندما تتصل content = codecs.open("myfile.txt", "r", "utf8").read()
content
سيكون في يونيكود.
برامج الترميز.فتح:http://docs.python.org/library/codecs.html?#codecs.open
إذا أخطأت في فهم شيء ما، فيرجى إبلاغي بذلك.
إذا لم تكن قد قمت بذلك بالفعل، فإنني أوصي بقراءة مقالة جويل حول الترميز الموحد والتشفير:http://www.joelonsoftware.com/articles/Unicode.html
جرب هذا:
import sys
print repr(sys.argv[1].decode('UTF-8'))
ربما عليك أن تحل محل CP437
أو CP1252
ل UTF-8
.يجب أن تكون قادرًا على استنتاج اسم الترميز الصحيح من مفتاح التسجيل HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP
قد يكون سطر الأوامر بترميز Windows.حاول فك تشفير الوسائط إلى unicode
أشياء:
args = [unicode(x, "iso-8859-9") for x in sys.argv]