اقرأ أحرف Unicode من وسيطات سطر الأوامر في Python 2.x على نظام التشغيل Windows

StackOverflow https://stackoverflow.com/questions/846850

سؤال

أريد أن يكون برنامج 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]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top