पायथन में एक स्ट्रिंग में प्रक्रिया से बचने के क्रम


112

कभी-कभी जब मुझे किसी फ़ाइल या उपयोगकर्ता से इनपुट मिलता है, तो मुझे उसमें भागने के क्रम के साथ एक स्ट्रिंग मिलती है। मैं उसी तरह से भागने के दृश्यों को संसाधित करना चाहता हूं, जैसे कि पायथन प्रक्रियाएं स्ट्रिंग साहित्यिकों में अनुक्रम से बचती हैं

उदाहरण के लिए, मान लें कि myStringइसे परिभाषित किया गया है:

>>> myString = "spam\\neggs"
>>> print(myString)
spam\neggs

मुझे एक फ़ंक्शन चाहिए (मैं इसे कॉल करूँगा process) जो ऐसा करता है:

>>> print(process(myString))
spam
eggs

यह महत्वपूर्ण है कि फ़ंक्शन पायथन में सभी एस्केप अनुक्रमों को संसाधित कर सकता है (ऊपर दिए गए लिंक में एक तालिका में सूचीबद्ध है)।

क्या पायथन के पास ऐसा करने के लिए कोई कार्य है?


1
हम्म, आप वास्तव में कैसे एक स्ट्रिंग की उम्मीद करेंगे जिसमें 'spam'+"eggs"+'''some'''+"""more"""संसाधित किया जाएगा?
Nas Banov

@ नेस बानोव यह एक अच्छी परीक्षा है। उस स्ट्रिंग में कोई एस्केप सीक्वेंस नहीं है, इसलिए यह प्रसंस्करण के बाद बिल्कुल वैसा ही होना चाहिए। myString = "'spam'+\"eggs\"+'''some'''+\"\"\"more\"\"\"", print(bytes(myString, "utf-8").decode("unicode_escape"))काम करने लगता है।
dln385

5
इस प्रश्न के अधिकांश उत्तरों में गंभीर समस्याएं हैं। ऐसा लगता है कि यूनिकोड को तोड़े बिना पायथन में भागने के दृश्यों को सम्मानित करने का कोई मानक तरीका नहीं है। @Rspeer द्वारा पोस्ट किया गया जवाब वह है जिसे मैंने ग्रेको के लिए अपनाया था क्योंकि यह अब तक सभी ज्ञात मामलों को संभालता है।
अपाला

जवाबों:


138

सही बात यह है कि स्ट्रिंग को डीकोड करने के लिए 'स्ट्रिंग-एस्केप' कोड का उपयोग करें।

>>> myString = "spam\\neggs"
>>> decoded_string = bytes(myString, "utf-8").decode("unicode_escape") # python3 
>>> decoded_string = myString.decode('string_escape') # python2
>>> print(decoded_string)
spam
eggs

एएसटी या eval का उपयोग न करें। स्ट्रिंग कोडेक्स का उपयोग करना अधिक सुरक्षित है।


3
नीचे हाथ, सबसे अच्छा समाधान! btw, डॉक्स द्वारा इसे "string_escape" (अंडरस्कोर के साथ) होना चाहिए, लेकिन किसी कारण से पैटर्न 'स्ट्रिंग एस्केप', 'स्ट्रिंग @ एस्केप' और whatnot में कुछ भी स्वीकार करता है ... मूल रूप से'string\W+escape'
Nas Banov

2
@Nas Banov प्रलेखन उस के बारे में एक छोटा सा उल्लेख करता है :Notice that spelling alternatives that only differ in case or use a hyphen instead of an underscore are also valid aliases; therefore, e.g. 'utf-8' is a valid alias for the 'utf_8' codec.
dln385

30
यह समाधान पर्याप्त नहीं है क्योंकि यह उस मामले को नहीं संभालता है जिसमें मूल स्ट्रिंग में वैध यूनिकोड वर्ण हैं। यदि आप कोशिश करते हैं: >>> print("juancarlo\\tañez".encode('utf-8').decode('unicode_escape')) आप मिलते हैं: juancarlo añez
अपाला

2
@ अपाला के साथ सहमत: यह काफी अच्छा नहीं है। Python2 और 3 में काम करने वाले संपूर्ण समाधान के लिए नीचे दिए गए रिस्पेर्स के उत्तर को देखें!
क्रिश्चियन आइचिंगर

2
चूंकि latin1मान लिया गया है unicode_escape, एनकोड / डीकोड बिट को फिर से करें, जैसेs.encode('utf-8').decode('unicode_escape').encode('latin1').decode('utf8')
मेटाटैस्टर

121

unicode_escape सामान्य रूप से काम नहीं करता है

यह पता चला है कि string_escapeया unicode_escapeसमाधान सामान्य रूप से काम नहीं करता है - विशेष रूप से, यह वास्तविक यूनिकोड की उपस्थिति में काम नहीं करता है।

यदि आप सुनिश्चित कर सकते हैं कि प्रत्येक गैर-एएससीआईआई चरित्र बच जाएगा (और याद रखें, पहले 128 वर्णों से परे कुछ भी गैर-एएससीआईआई है), unicode_escapeआपके लिए सही काम करेगा। लेकिन अगर आपके स्ट्रिंग में पहले से ही कोई शाब्दिक गैर-एएससीआईआई अक्षर हैं, तो चीजें गलत हो जाएंगी।

unicode_escapeमूल रूप से बाइट्स को यूनिकोड पाठ में बदलने के लिए डिज़ाइन किया गया है। लेकिन कई स्थानों में - उदाहरण के लिए, पायथन स्रोत कोड - स्रोत डेटा पहले से ही यूनिकोड पाठ है।

एकमात्र तरीका यह सही ढंग से काम कर सकता है यदि आप पाठ को पहले बाइट्स में एन्कोड करते हैं। यूटीएफ -8 सभी पाठों के लिए समझदार एन्कोडिंग है, इसलिए काम करना चाहिए, है ना?

निम्नलिखित उदाहरण पायथन 3 में हैं, ताकि स्ट्रिंग शाब्दिक क्लीनर हो, लेकिन पायथन 2 और 3 दोनों पर थोड़ी अलग अभिव्यक्तियों के साथ एक ही समस्या मौजूद है।

>>> s = 'naïve \\t test'
>>> print(s.encode('utf-8').decode('unicode_escape'))
naïve   test

खैर, यह गलत है।

पाठ में डिकोड करने वाले कोडेक्स का उपयोग करने का नया अनुशंसित तरीका codecs.decodeसीधे कॉल करना है। क्या उससे मदद हुई?

>>> import codecs
>>> print(codecs.decode(s, 'unicode_escape'))
naïve   test

हर्गिज नहीं। (इसके अलावा, उपरोक्त पाइथन 2 पर एक यूनिकोडर्रम है)

unicode_escapeकोडेक, जैसा कि इसके नाम के बावजूद, पता चला है ग्रहण करने के लिए है कि सभी गैर- ASCII बाइट्स लैटिन -1 (ISO-8859-1) एन्कोडिंग में कर रहे हैं। तो आपको इसे इस तरह करना होगा:

>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve    test

लेकिन यह भयानक है। यह आपको 256 लैटिन -1 वर्णों तक सीमित करता है, जैसे कि यूनिकोड का आविष्कार कभी नहीं हुआ था!

>>> print('Ernő \\t Rubik'.encode('latin-1').decode('unicode_escape'))
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0151'
in position 3: ordinal not in range(256)

समस्या को हल करने के लिए एक नियमित अभिव्यक्ति जोड़ना

(हैरानी की बात है, अब हमें दो समस्याएं नहीं हैं।)

हमें जो करने की आवश्यकता है, केवल unicode_escapeडिकोडर को उन चीजों पर लागू करें जिन्हें हम ASCII पाठ के लिए निश्चित हैं। विशेष रूप से, हम इसे केवल वैध पायथन एस्केप सीक्वेंस पर लागू करने के लिए सुनिश्चित कर सकते हैं, जो कि ASCII पाठ होने की गारंटी है।

योजना यह है कि हम एक नियमित अभिव्यक्ति का उपयोग करके एस्केप सीक्वेंस प्राप्त करेंगे, और एक फ़ंक्शन का उपयोग तर्क के रूप में re.subउन्हें उनके अनपेक्षित मान से बदलने के लिए करेंगे।

import re
import codecs

ESCAPE_SEQUENCE_RE = re.compile(r'''
    ( \\U........      # 8-digit hex escapes
    | \\u....          # 4-digit hex escapes
    | \\x..            # 2-digit hex escapes
    | \\[0-7]{1,3}     # Octal escapes
    | \\N\{[^}]+\}     # Unicode characters by name
    | \\[\\'"abfnrtv]  # Single-character escapes
    )''', re.UNICODE | re.VERBOSE)

def decode_escapes(s):
    def decode_match(match):
        return codecs.decode(match.group(0), 'unicode-escape')

    return ESCAPE_SEQUENCE_RE.sub(decode_match, s)

और उसके साथ:

>>> print(decode_escapes('Ernő \\t Rubik'))
Ernő     Rubik

2
हमें इस तरह के और अधिक प्रकार के उत्तरों की आवश्यकता है। धन्यवाद।
v.oddou

क्या यह os.sepसब साथ काम करता है ? मैं यह करने की कोशिश कर रहा हूं: patt = '^' + self.prefix + os.sep ; name = sub(decode_escapes(patt), '', name)और यह काम नहीं कर रहा है। नई लाइन के स्थान पर सेमीकोलन है।
शुद्ध

@Pureferret मुझे वास्तव में यकीन नहीं है कि आप क्या पूछ रहे हैं, लेकिन आपको शायद इसे स्ट्रिंग्स पर नहीं चलाना चाहिए, जहां बैकस्लैश का एक अलग अर्थ है, जैसे कि विंडोज फ़ाइल पथ। (क्या आपका क्या os.sepहै?) यदि आपके पास अपने विंडोज निर्देशिका नामों में बैकस्क्स्ड एस्केप अनुक्रम हैं, तो स्थिति बहुत अधिक अप्राप्य है।
rspeer

बच निकलने का क्रम उनमें नहीं बचता है, लेकिन मुझे 'फर्जी भागने की
कड़ी

यह बताता है कि आपने बैकस्लैश के साथ कुछ अन्य नियमित अभिव्यक्ति को समाप्त कर दिया: stackoverflow.com/questions/4427174/…
rspeer

33

अजगर 3 के लिए वास्तव में सही और सुविधाजनक उत्तर:

>>> import codecs
>>> myString = "spam\\neggs"
>>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
spam
eggs
>>> myString = "naïve \\t test"
>>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
naïve    test

विवरण के बारे में codecs.escape_decode:

  • codecs.escape_decode एक बाइट्स-दर-बाइट डिकोडर है
  • codecs.escape_decodeडिकोडी एससीआई एस्केप सीक्वेंस, जैसे: b"\\n"-> b"\n", b"\\xce"-> b"\xce"
  • codecs.escape_decode बाइट ऑब्जेक्ट के एन्कोडिंग के बारे में परवाह करने या जानने की ज़रूरत नहीं है, लेकिन बची हुई बाइट्स की एन्कोडिंग को बाकी ऑब्जेक्ट के एन्कोडिंग से मेल खाना चाहिए।

पृष्ठभूमि:

  • @rspeer सही है: unicode_escapepython3 के लिए गलत समाधान है। ऐसा इसलिए है क्योंकि unicode_escapeडिकोड बाइट्स से बच गए, फिर बाइट्स को यूनिकोड स्ट्रिंग में डिकोड करते हैं, लेकिन दूसरे ऑपरेशन के लिए किस कोडेक का उपयोग करना है, इसके बारे में कोई जानकारी नहीं मिलती है।
  • @ जरब सही है: एएसटी या ईवैल से बचें।
  • मुझे पहली बार इस उत्तरcodecs.escape_decode से पता चला कि "पायथन 3 में मैं कैसे .d timecode ('स्ट्रिंग-एस्केप') कर सकता हूं?" । जैसा कि उत्तर में कहा गया है, उस समारोह को वर्तमान में अजगर 3 के लिए प्रलेखित नहीं किया गया है।

यह वास्तविक उत्तर है: (बहुत बुरा यह एक खराब-दस्तावेज़ित कार्य पर निर्भर करता है।
jwd

5
यह उन स्थितियों के लिए उत्तर है जहां आपके पास \xबची हुई सीक्वेंस UTF-8 बाइट्स से बच जाती हैं । लेकिन क्योंकि यह बाइट्स को बाइट्स में डिकोड करता है, इसलिए यह नहीं है - और गैर-एएससीआईआई यूनिकोड वर्णों के किसी भी पलायन को डीकोड कर सकता है, जैसे कि \uपलायन।
rspeer

सिर्फ एक FYI करें, यह फ़ंक्शन तकनीकी रूप से सार्वजनिक नहीं है। देख bugs.python.org/issue30588
Hack5

8

ast.literal_evalसमारोह करीब आता है, लेकिन यह स्ट्रिंग ठीक से पहले उद्धृत होने की उम्मीद करेंगे।

बेशक बैकस्लैश एस्केप के पायथन की व्याख्या इस बात पर निर्भर करती है कि स्ट्रिंग को कैसे उद्धृत किया जाता है ( ""बनाम r""बनाम u"", ट्रिपल उद्धरण, आदि) ताकि आप उपयोगकर्ता इनपुट को उपयुक्त उद्धरणों में लपेट कर और पास करना चाहें literal_eval। इसे उद्धरणों में लपेटने literal_evalसे एक संख्या, टपल, शब्दकोश, इत्यादि को वापस आने से रोका जा सकेगा ।

यदि उपयोगकर्ता स्ट्रिंग के चारों ओर लपेटने का इरादा रखते हैं, तो उस प्रकार के उद्धरणों को अस्वीकार कर सकता है, जो अभी भी गलत हैं।


समझा। जैसा कि आप कहते हैं myString = "\"\ndoBadStuff()\n\"", यह संभावित रूप से खतरनाक print(ast.literal_eval('"' + myString + '"'))प्रतीत होता है : कोड चलाने की कोशिश करने लगता है। की ast.literal_evalतुलना में कोई भिन्न / सुरक्षित कैसे है eval?
dln385 4

5
@ dln385: literal_evalकभी भी कोड निष्पादित नहीं करता है। प्रलेखन से, "इसका उपयोग उन मूल्यों को पार्स करने की आवश्यकता के बिना अविश्वसनीय स्रोतों से पायथन अभिव्यक्तियों वाले तार के सुरक्षित मूल्यांकन के लिए किया जा सकता है।"
ग्रेग हेविगेल

2

यह इसे करने का एक बुरा तरीका है, लेकिन यह मेरे लिए काम करता है जब एक स्ट्रिंग तर्क में पारित बच गए ऑक्टल्स की व्याख्या करने की कोशिश की जाती है।

input_string = eval('b"' + sys.argv[1] + '"')

यह ध्यान देने योग्य है कि eval और ast.literal_eval के बीच अंतर है (eval अधिक असुरक्षित तरीका है)। देखअजगर का उपयोग करना () बनाम ast.literal_eval ()?


0

नीचे दिए गए कोड को स्ट्रिंग पर प्रदर्शित होने के लिए \ n काम करना चाहिए।

import string

our_str = 'The String is \\n, \\n and \\n!'
new_str = string.replace(our_str, '/\\n', '/\n', 1)
print(new_str)

1
यह लिखित के रूप में काम नहीं करता है (फॉरवर्ड स्लैश replaceकुछ भी नहीं करते हैं), बेतहाशा आउटडेटेड एपीआई का उपयोग करता है ( stringइस प्रकार के मॉड्यूल कार्यों को पायथन 2.0 के रूप में चित्रित किया गया strहै, विधियों द्वारा प्रतिस्थापित किया गया है, और पायथन 3 में पूरी तरह से चला गया है), और केवल औसत एक ही नई पंक्ति की जगह के विशिष्ट मामले को संभालता है, सामान्य बच प्रसंस्करण नहीं।
शैडो रेंजर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.