python - पाइथन में उद्धृत सब्सट्रिंग को संरक्षित-रिक्त स्थान से एक स्ट्रिंग को विभाजित करें




regex (10)

आप shlex मॉड्यूल से विभाजित करना चाहते हैं।

>>> import shlex
>>> shlex.split('this is "a test"')
['this', 'is', 'a test']

यह वही करना चाहिए जो आप चाहते हैं।

मेरे पास एक स्ट्रिंग है जो इस तरह है:

this is "a test"

मैं उद्धरण के भीतर रिक्त स्थान को अनदेखा करते हुए अंतरिक्ष द्वारा इसे विभाजित करने के लिए पाइथन में कुछ लिखने की कोशिश कर रहा हूं। नतीजा मैं देख रहा हूं:

['this','is','a test']

पुनश्च। मुझे पता है कि आप पूछने जा रहे हैं "उद्धरण के भीतर कोट्स होने पर क्या होता है, ठीक है, मेरे आवेदन में, ऐसा कभी नहीं होगा।


आपके उपयोग के मामले के आधार पर, आप सीएसवी मॉड्यूल भी देखना चाहेंगे:

import csv
lines = ['this is "a string"', 'and more "stuff"']
for row in csv.reader(lines, delimiter=" "):
    print row

आउटपुट:

['this', 'is', 'a string']
['and', 'more', 'stuff']

उद्धरणों को संरक्षित करने के लिए इस फ़ंक्शन का उपयोग करें:

def getArgs(s):
    args = []
    cur = ''
    inQuotes = 0
    for char in s.strip():
        if char == ' ' and not inQuotes:
            args.append(cur)
            cur = ''
        elif char == '"' and not inQuotes:
            inQuotes = 1
            cur += char
        elif char == '"' and inQuotes:
            inQuotes = 0
            cur += char
        else:
            cur += char
    args.append(cur)
    return args

ऊपर चर्चा की गई श्लेक्स के साथ यूनिकोड मुद्दे (शीर्ष उत्तर) को http://bugs.python.org/issue6988#msg146200 अनुसार 2.7.2+ में हल किया जा सकता है (परोक्ष रूप से)

(अलग जवाब क्योंकि मैं टिप्पणी नहीं कर सकता)


चूंकि इस प्रश्न को रेगेक्स के साथ टैग किया गया है, इसलिए मैंने रेगेक्स दृष्टिकोण को आजमाने का फैसला किया। मैं पहले उद्धरण भागों में सभी रिक्त स्थान को \ x00 के साथ प्रतिस्थापित करता हूं, फिर रिक्त स्थान से विभाजित होता हूं, फिर प्रत्येक भाग में \ x00 वापस रिक्त स्थान पर प्रतिस्थापित करता है।

दोनों संस्करण एक ही काम करते हैं, लेकिन स्प्लिटर स्प्लिटर 2 थोड़ा और पठनीय है।

import re

s = 'this is "a test" some text "another test"'

def splitter(s):
    def replacer(m):
        return m.group(0).replace(" ", "\x00")
    parts = re.sub('".+?"', replacer, s).split()
    parts = [p.replace("\x00", " ") for p in parts]
    return parts

def splitter2(s):
    return [p.replace("\x00", " ") for p in re.sub('".+?"', lambda m: m.group(0).replace(" ", "\x00"), s).split()]

print splitter2(s)

मैं यहां रेगेक्स दृष्टिकोण देखता हूं जो जटिल और / या गलत दिखते हैं। यह मुझे आश्चर्यचकित करता है, क्योंकि रेगेक्स सिंटैक्स आसानी से "व्हाइटस्पेस या चीज़-घेरे-बाय-कोट्स" का वर्णन कर सकता है, और अधिकांश रेगेक्स इंजन (पायथन सहित) एक रेगेक्स पर विभाजित हो सकते हैं। तो यदि आप रेगेक्स का उपयोग करने जा रहे हैं, तो बस इतना क्यों न कहें कि आपका क्या मतलब है ?:

test = 'this is "a test"'  # or "this is 'a test'"
# pieces = [p for p in re.split("( |[\\\"'].*[\\\"'])", test) if p.strip()]
# From comments, use this:
pieces = [p for p in re.split("( |\\\".*?\\\"|'.*?')", test) if p.strip()]

स्पष्टीकरण:

[\\\"'] = double-quote or single-quote
.* = anything
( |X) = space or X
.strip() = remove space and empty-string separators

हालांकि, शेलेक्स शायद अधिक सुविधाएं प्रदान करता है।


मैं स्क्विड लॉग की 70,000,000 लाइनों को संसाधित करने के लिए shlex.split का उपयोग करता हूं, यह बहुत धीमा है। तो मैं फिर से स्विच किया।

यदि आपके पास शेलेक्स के साथ प्रदर्शन समस्या है, तो कृपया इसे आज़माएं।

import re

def line_split(line):
    return re.findall(r'[^"\s]\S*|".+?"', line)

यदि आपको सरल से उप स्ट्रिंग्स की परवाह नहीं है

>>> 'a short sized string with spaces '.split()

प्रदर्शन:

>>> s = " ('a short sized string with spaces '*100).split() "
>>> t = timeit.Timer(stmt=s)
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
171.39 usec/pass

या स्ट्रिंग मॉड्यूल

>>> from string import split as stringsplit; 
>>> stringsplit('a short sized string with spaces '*100)

प्रदर्शन: स्ट्रिंग मॉड्यूल स्ट्रिंग विधियों से बेहतर प्रदर्शन करता प्रतीत होता है

>>> s = "stringsplit('a short sized string with spaces '*100)"
>>> t = timeit.Timer(s, "from string import split as stringsplit")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
154.88 usec/pass

या आप आरई इंजन का उपयोग कर सकते हैं

>>> from re import split as resplit
>>> regex = '\s+'
>>> medstring = 'a short sized string with spaces '*100
>>> resplit(regex, medstring)

प्रदर्शन

>>> s = "resplit(regex, medstring)"
>>> t = timeit.Timer(s, "from re import split as resplit; regex='\s+'; medstring='a short sized string with spaces '*100")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
540.21 usec/pass

बहुत लंबे तारों के लिए आपको पूरी स्ट्रिंग को स्मृति में लोड नहीं करना चाहिए और इसके बजाय या तो लाइनों को विभाजित करना चाहिए या पुनरावृत्त लूप का उपयोग करना चाहिए


हम्म, "उत्तर" बटन नहीं ढूंढ रहा है ... वैसे भी, यह उत्तर केट के दृष्टिकोण पर आधारित है, लेकिन बच निकले उद्धरण वाले सबस्ट्रिंग्स के साथ स्ट्रिंग्स को सही ढंग से विभाजित करता है और सबस्ट्रिंग्स के प्रारंभ और अंत उद्धरण को भी हटा देता है:

  [i.strip('"').strip("'") for i in re.split(r'(\s+|(?<!\\)".*?(?<!\\)"|(?<!\\)\'.*?(?<!\\)\')', string) if i.strip()]

यह 'This is " a \\\"test\\\"\\\'s substring"' जैसे तारों पर काम करता 'This is " a \\\"test\\\"\\\'s substring"' (पाइथन को भागने से हटाने के लिए पागलपन दुर्भाग्य से आवश्यक है)।

यदि लौटाई गई सूची में तारों में परिणामी भाग निकलना चाहते हैं, तो आप फ़ंक्शन के इस छोटे से परिवर्तित संस्करण का उपयोग कर सकते हैं:

[i.strip('"').strip("'").decode('string_escape') for i in re.split(r'(\s+|(?<!\\)".*?(?<!\\)"|(?<!\\)\'.*?(?<!\\)\')', string) if i.strip()]

shlex मॉड्यूल, विशेष रूप से shlex.split पर एक नज़र shlex.split

>>> import shlex
>>> shlex.split('This is "a test"')
['This', 'is', 'a test']






regex