पायथन में `string.split ()` का जनरेटर संस्करण है?


113

string.split()एक सूची उदाहरण देता है । क्या कोई ऐसा संस्करण है जो बदले में एक जनरेटर देता है ? क्या जनरेटर संस्करण होने के खिलाफ कोई कारण हैं?


3
यह प्रश्न संबंधित हो सकता है।
ब्योर्न पोलेक्स

1
कारण यह है कि एक मामले के बारे में सोचना बहुत मुश्किल है जहां यह उपयोगी है। आप ऐसा क्यों चाहते हैं?
ग्लेन मेनार्ड

10
@ ग्लेन: हाल ही में मैंने एक लंबे स्ट्रिंग को एन शब्दों के टुकड़ों में विभाजित करने के बारे में एक प्रश्न देखा। समाधान में से splitएक स्ट्रिंग और फिर के परिणाम पर काम कर रहे एक जनरेटर लौटा split। अगर वहाँ splitएक जनरेटर के साथ शुरू करने के लिए लौटने के लिए एक रास्ता था कि मुझे सोच रहा था ।
मनोज गोविंदन

5
पायथन इश्यू ट्रैकर पर एक प्रासंगिक चर्चा है: bugs.python.org/issue17343
saffsd

@GlennMaynard यह वास्तव में बड़े नंगे स्ट्रिंग / फ़ाइल पार्सिंग के लिए उपयोगी हो सकता है, लेकिन कोई भी स्वयं को पीसा डीएफए और उपज का उपयोग करके जनरेटर पार्सर को बहुत आसान लिख सकता है
दिमित्री पोनतोव

जवाबों:


77

यह अत्यधिक संभावित है कि re.finditerकाफी न्यूनतम मेमोरी ओवरहेड का उपयोग करता है।

def split_iter(string):
    return (x.group(0) for x in re.finditer(r"[A-Za-z']+", string))

डेमो:

>>> list( split_iter("A programmer's RegEx test.") )
['A', "programmer's", 'RegEx', 'test']

संपादित करें: मैंने अभी पुष्टि की है कि यह अजगर 3.2.1 में निरंतर स्मृति लेता है, यह मानते हुए कि मेरी परीक्षण पद्धति सही थी। मैंने बहुत बड़े आकार (1GB या तो) की एक स्ट्रिंग बनाई, फिर एक forलूप के साथ चलने वाले के माध्यम से पुनरावृत्त (एक सूची समझ नहीं है, जो अतिरिक्त मेमोरी उत्पन्न होती है)। इससे मेमोरी की ध्यान देने योग्य वृद्धि नहीं हुई (अर्थात, यदि मेमोरी में वृद्धि हुई थी, तो यह 1 जीबी स्ट्रिंग से काफी कम थी)।


5
अति उत्कृष्ट! मैं खोजकर्ता के बारे में भूल गया था। यदि कोई स्प्लिटलाइन जैसा कुछ करने में रुचि रखता है, तो मैं इस आरईई: '(? *। \ N। + $) का उपयोग करने का सुझाव दूंगा। str.splitlines ट्रेनिंग न्यूलाइन को काटता है हालांकि (कुछ ऐसा जो मुझे वास्तव में पसंद नहीं है ... ); यदि आप व्यवहार के उस हिस्से को दोहराना चाहते हैं, तो आप ग्रुपिंग का उपयोग कर सकते हैं: (m.group (2) या m.group (3) में m के लिए re.finditer ('((*। *) \ n | + (+)। $) ', एस)। पुनश्च: मुझे लगता है कि आरई में बाहरी पेरेन की जरूरत नहीं है; मैं बस का उपयोग करने के बारे में असहज महसूस करता हूँ | बिना
पराग

3
प्रदर्शन के बारे में क्या? फिर से मिलान धीमी खोज होना चाहिए।
अनातोली टेकटोनिक

1
आप इस स्प्लिट_टर फ़ंक्शन को कैसे काम करने के लिए फिर से लिखेंगे a_string.split("delimiter")?
रॉबर्ट्स

विभाजित नियमित अभिव्यक्ति को वैसे भी स्वीकार करता है, इसलिए यह वास्तव में तेज़ नहीं है, यदि आप किसी प्रचलित अगले फैशन में दिए गए मान का उपयोग करना चाहते हैं, तो नीचे दिए गए मेरे उत्तर को देखें ...
Veltzer Doron

str.split()नियमित अभिव्यक्ति को स्वीकार नहीं करता है, कि re.split()आप सोच रहे हैं ...
एलेक्सिस

17

सबसे कुशल तरीका है कि मैं इसे विधि के offsetपैरामीटर का उपयोग करके लिखने के लिए सोच सकता हूं str.find()। यह बहुत सारे मेमोरी के उपयोग से बचा जाता है, और जब आवश्यकता नहीं होती है तब regexp के ओवरहेड पर निर्भर करता है।

[संपादित करें 2016-8-2: रेगेक्स सेपरेटर को वैकल्पिक रूप से समर्थन करने के लिए इसे अपडेट किया गया]

def isplit(source, sep=None, regex=False):
    """
    generator version of str.split()

    :param source:
        source string (unicode or bytes)

    :param sep:
        separator to split on.

    :param regex:
        if True, will treat sep as regular expression.

    :returns:
        generator yielding elements of string.
    """
    if sep is None:
        # mimic default python behavior
        source = source.strip()
        sep = "\\s+"
        if isinstance(source, bytes):
            sep = sep.encode("ascii")
        regex = True
    if regex:
        # version using re.finditer()
        if not hasattr(sep, "finditer"):
            sep = re.compile(sep)
        start = 0
        for m in sep.finditer(source):
            idx = m.start()
            assert idx >= start
            yield source[start:idx]
            start = m.end()
        yield source[start:]
    else:
        # version using str.find(), less overhead than re.finditer()
        sepsize = len(sep)
        start = 0
        while True:
            idx = source.find(sep, start)
            if idx == -1:
                yield source[start:]
                return
            yield source[start:idx]
            start = idx + sepsize

यह आप की तरह इस्तेमाल किया जा सकता है ...

>>> print list(isplit("abcb","b"))
['a','c','']

जबकि स्ट्रिंग में हर बार ढूंढने () या स्लाइसिंग के लिए थोड़ी लागत की मांग होती है, यह न्यूनतम होना चाहिए क्योंकि स्ट्रिंग्स को स्मृति में विपरीत सरणियों के रूप में दर्शाया जाता है।


10

यह split()लागू किया गया जनरेटर संस्करण है जिसके माध्यम से re.search()बहुत सारे सबस्ट्रिंग को आवंटित करने की समस्या नहीं है।

import re

def itersplit(s, sep=None):
    exp = re.compile(r'\s+' if sep is None else re.escape(sep))
    pos = 0
    while True:
        m = exp.search(s, pos)
        if not m:
            if pos < len(s) or sep is not None:
                yield s[pos:]
            break
        if pos < m.start() or sep is not None:
            yield s[pos:m.start()]
        pos = m.end()


sample1 = "Good evening, world!"
sample2 = " Good evening, world! "
sample3 = "brackets][all][][over][here"
sample4 = "][brackets][all][][over][here]["

assert list(itersplit(sample1)) == sample1.split()
assert list(itersplit(sample2)) == sample2.split()
assert list(itersplit(sample3, '][')) == sample3.split('][')
assert list(itersplit(sample4, '][')) == sample4.split('][')

EDIT: यदि कोई विभाजक वर्ण नहीं दिया गया है, तो आसपास के व्हाट्सएप को ठीक करना।


12
यह किसी से बेहतर क्यों है re.finditer?
एरिक कप्लून

@ErikKaplun क्योंकि आइटम के लिए रेगेक्स तर्क उनके विभाजकों की तुलना में अधिक जटिल हो सकता है। मेरे मामले में, मैं प्रत्येक पंक्ति को व्यक्तिगत रूप से संसाधित करना चाहता था, इसलिए यदि कोई रेखा मिलान करने में विफल रही तो मैं वापस रिपोर्ट कर सकता हूं।
रोविक्को

9

क्या प्रस्तावित विभिन्न तरीकों पर कुछ प्रदर्शन परीक्षण किया गया था (मैं उन्हें यहां नहीं दोहराऊंगा)। कुछ परिणाम:

  • str.split (डिफ़ॉल्ट = 0.3461570239996945
  • मैनुअल खोज (चरित्र द्वारा) (डेव वेब के उत्तर में से एक) = 0.8260340550004912
  • re.finditer (निंजेजको का उत्तर) = 0.698872097000276
  • str.find (एली कोलिन्स के जवाबों में से एक) = 0.7230395330007013
  • itertools.takewhile (इग्नासियो वाज़केज़-अब्राम्स उत्तर) = 2.023023967998597
  • str.split(..., maxsplit=1) पुनरावर्तन = एन / ए /

Complete पुनरावृत्ति उत्तर ( string.splitसाथ maxsplit = 1) एक उचित समय में पूरा होने में विफल होते हैं, दी गई string.splitगति वे छोटे तारों पर बेहतर काम कर सकते हैं, लेकिन फिर मैं छोटे तारों के लिए उपयोग-मामला नहीं देख सकता, जहां मेमोरी वैसे भी कोई समस्या नहीं है।

का उपयोग करके परीक्षण किया timeitगया:

the_text = "100 " * 9999 + "100"

def test_function( method ):
    def fn( ):
        total = 0

        for x in method( the_text ):
            total += int( x )

        return total

    return fn

यह एक और सवाल उठाता है कि string.splitइसकी मेमोरी उपयोग के बावजूद इतनी तेजी से क्यों बढ़ रही है।


1
ऐसा इसलिए है क्योंकि मेमोरी सीपीयू की तुलना में धीमी है और इस मामले में, सूची को उन हिस्सों से लोड किया जाता है जहां अन्य सभी तत्व द्वारा लोड किए गए तत्व हैं। एक ही नोट पर, कई शिक्षाविद आपको बताएंगे कि लिंक की गई सूचियां तेज़ हैं और उनकी जटिलता कम है, जबकि आपका कंप्यूटर अक्सर सरणियों के साथ तेज़ होगा, जिसे अनुकूलित करना आसान लगता है। आप यह नहीं मान सकते कि कोई विकल्प दूसरे की तुलना में तेज़ है, उसका परीक्षण करें! परीक्षण के लिए +1।
बेनोइट पी

प्रॉसेसिंग चेन के अगले चरणों में समस्या उत्पन्न होती है। यदि आप फिर एक विशिष्ट हिस्सा ढूंढना चाहते हैं और जब आप इसे ढूंढते हैं तो बाकी की अनदेखी करते हैं, तो आपके पास अंतर्निहित समाधान के बजाय एक जनरेटर आधारित विभाजन का उपयोग करने का औचित्य है।
jgomo3

6

यहाँ मेरा कार्यान्वयन है, जो कि, अन्य उत्तरों की तुलना में बहुत अधिक तेज और अधिक पूर्ण है। इसमें अलग-अलग मामलों के लिए 4 अलग उपखंड हैं।

मैं सिर्फ मुख्य str_splitसमारोह के डॉकस्ट्रिंग की नकल करूँगा :


str_split(s, *delims, empty=None)

sशेष तर्कों द्वारा स्ट्रिंग को विभाजित करें , संभवतः खाली भागों को छोड़ना ( emptyकीवर्ड तर्क इसके लिए जिम्मेदार है)। यह एक जनरेटर फ़ंक्शन है।

जब केवल एक सीमांकक की आपूर्ति की जाती है, तो स्ट्रिंग को इसके द्वारा विभाजित किया जाता है। emptyफिर Trueडिफ़ॉल्ट रूप से है।

str_split('[]aaa[][]bb[c', '[]')
    -> '', 'aaa', '', 'bb[c'
str_split('[]aaa[][]bb[c', '[]', empty=False)
    -> 'aaa', 'bb[c'

जब कई सीमांकक की आपूर्ति की जाती है, तो स्ट्रिंग को डिफ़ॉल्ट रूप से उन सीमांकक के सबसे लंबे संभव अनुक्रमों द्वारा विभाजित किया जाता है, या, यदि emptyसेट किया जाता है True, तो सीमांकक के बीच खाली तार भी शामिल होते हैं। ध्यान दें कि इस मामले में सीमांकक केवल एकल वर्ण हो सकते हैं।

str_split('aaa, bb : c;', ' ', ',', ':', ';')
    -> 'aaa', 'bb', 'c'
str_split('aaa, bb : c;', *' ,:;', empty=True)
    -> 'aaa', '', 'bb', '', '', 'c', ''

जब कोई सीमांकक की आपूर्ति नहीं की जाती string.whitespaceहै, तो इसका उपयोग किया जाता है, इसलिए इसका प्रभाव वैसा ही होता है, जैसे कि str.split()यह फ़ंक्शन एक जनरेटर है।

str_split('aaa\\t  bb c \\n')
    -> 'aaa', 'bb', 'c'

import string

def _str_split_chars(s, delims):
    "Split the string `s` by characters contained in `delims`, including the \
    empty parts between two consecutive delimiters"
    start = 0
    for i, c in enumerate(s):
        if c in delims:
            yield s[start:i]
            start = i+1
    yield s[start:]

def _str_split_chars_ne(s, delims):
    "Split the string `s` by longest possible sequences of characters \
    contained in `delims`"
    start = 0
    in_s = False
    for i, c in enumerate(s):
        if c in delims:
            if in_s:
                yield s[start:i]
                in_s = False
        else:
            if not in_s:
                in_s = True
                start = i
    if in_s:
        yield s[start:]


def _str_split_word(s, delim):
    "Split the string `s` by the string `delim`"
    dlen = len(delim)
    start = 0
    try:
        while True:
            i = s.index(delim, start)
            yield s[start:i]
            start = i+dlen
    except ValueError:
        pass
    yield s[start:]

def _str_split_word_ne(s, delim):
    "Split the string `s` by the string `delim`, not including empty parts \
    between two consecutive delimiters"
    dlen = len(delim)
    start = 0
    try:
        while True:
            i = s.index(delim, start)
            if start!=i:
                yield s[start:i]
            start = i+dlen
    except ValueError:
        pass
    if start<len(s):
        yield s[start:]


def str_split(s, *delims, empty=None):
    """\
Split the string `s` by the rest of the arguments, possibly omitting
empty parts (`empty` keyword argument is responsible for that).
This is a generator function.

When only one delimiter is supplied, the string is simply split by it.
`empty` is then `True` by default.
    str_split('[]aaa[][]bb[c', '[]')
        -> '', 'aaa', '', 'bb[c'
    str_split('[]aaa[][]bb[c', '[]', empty=False)
        -> 'aaa', 'bb[c'

When multiple delimiters are supplied, the string is split by longest
possible sequences of those delimiters by default, or, if `empty` is set to
`True`, empty strings between the delimiters are also included. Note that
the delimiters in this case may only be single characters.
    str_split('aaa, bb : c;', ' ', ',', ':', ';')
        -> 'aaa', 'bb', 'c'
    str_split('aaa, bb : c;', *' ,:;', empty=True)
        -> 'aaa', '', 'bb', '', '', 'c', ''

When no delimiters are supplied, `string.whitespace` is used, so the effect
is the same as `str.split()`, except this function is a generator.
    str_split('aaa\\t  bb c \\n')
        -> 'aaa', 'bb', 'c'
"""
    if len(delims)==1:
        f = _str_split_word if empty is None or empty else _str_split_word_ne
        return f(s, delims[0])
    if len(delims)==0:
        delims = string.whitespace
    delims = set(delims) if len(delims)>=4 else ''.join(delims)
    if any(len(d)>1 for d in delims):
        raise ValueError("Only 1-character multiple delimiters are supported")
    f = _str_split_chars if empty else _str_split_chars_ne
    return f(s, delims)

यह फ़ंक्शन पायथन 3 में काम करता है, और एक आसान, हालांकि काफी बदसूरत है, इसे 2 और 3 दोनों संस्करणों में काम करने के लिए फिक्स लागू किया जा सकता है। फ़ंक्शन की पहली पंक्तियों को निम्न में बदलना चाहिए:

def str_split(s, *delims, **kwargs):
    """...docstring..."""
    empty = kwargs.get('empty')

3

नहीं, लेकिन इसका उपयोग करना आसान होना चाहिए itertools.takewhile()

संपादित करें:

बहुत सरल, आधा टूटा हुआ कार्यान्वयन:

import itertools
import string

def isplitwords(s):
  i = iter(s)
  while True:
    r = []
    for c in itertools.takewhile(lambda x: not x in string.whitespace, i):
      r.append(c)
    else:
      if r:
        yield ''.join(r)
        continue
      else:
        raise StopIteration()

@ इग्नासियो: डॉक्स में उदाहरण के उपयोग की व्याख्या करने के लिए पूर्णांकों की एक सूची का उपयोग करता है takeWhilepredicateएक स्ट्रिंग को शब्दों में विभाजित करने के लिए क्या अच्छा होगा (डिफ़ॉल्ट split) का उपयोग करके takeWhile()?
मनोज गोविंदन

में उपस्थिति के लिए देखें string.whitespace
इग्नासियो वाज़केज़-अब्राम्स

विभाजक के कई वर्ण हो सकते हैं,'abc<def<>ghi<><>lmn'.split('<>') == ['abc<def', 'ghi', '', 'lmn']
kennytm

@ इग्नासियो: क्या आप अपने जवाब में एक उदाहरण जोड़ सकते हैं?
मनोज गोविंदन

1
लिखने में आसान है, लेकिन परिमाण के कई क्रम धीमे हैं। यह एक ऑपरेशन है जिसे वास्तव में मूल कोड में लागू किया जाना चाहिए।
ग्लेन मेनार्ड

3

मुझे जनरेटर संस्करण के लिए कोई स्पष्ट लाभ नहीं दिखता है split()। जेनरेटर ऑब्जेक्ट में पूरी स्ट्रिंग समाहित करने वाली है ताकि आप जेनरेटर लगाकर किसी भी मेमोरी को सेव न कर सकें।

यदि आप एक लिखना चाहते हैं तो यह काफी आसान होगा, हालांकि:

import string

def gsplit(s,sep=string.whitespace):
    word = []

    for c in s:
        if c in sep:
            if word:
                yield "".join(word)
                word = []
        else:
            word.append(c)

    if word:
        yield "".join(word)

3
आप प्रत्येक उपयोग किए गए भाग में स्ट्रिंग की दूसरी प्रतिलिपि संग्रहीत नहीं करने के साथ, प्लस सरणी और ऑब्जेक्ट ओवरहेड (जो आमतौर पर स्वयं स्ट्रिंग्स की तुलना में अधिक है) का उपयोग करके मेमोरी को आधा कर देंगे। यह आम तौर पर कोई फर्क नहीं पड़ता, हालांकि (यदि आप स्ट्रिंग्स को इतना बड़ा विभाजित कर रहे हैं कि यह मायने रखता है, तो आप शायद कुछ गलत कर रहे हैं), और यहां तक ​​कि एक देशी सी जनरेटर कार्यान्वयन हमेशा एक ही बार में करने की तुलना में काफी धीमा होगा।
ग्लेन मेनार्ड

@ ग्लेन मेनार्ड - मुझे बस यही एहसास हुआ। मैं किसी कारण के लिए मैं मूल रूप से जनरेटर एक संदर्भ के बजाय स्ट्रिंग की एक प्रति स्टोर करेगा। एक त्वरित जांच id()मुझे सही लगा। और स्पष्ट रूप से जब तक तार अपरिवर्तनीय होते हैं, तब आपको इस बारे में चिंता करने की ज़रूरत नहीं है कि आप मूल स्ट्रिंग को बदलने के बारे में किसी को चिंता करने की ज़रूरत नहीं है।
डेव वेब

6
एक जनरेटर का उपयोग करने में मुख्य बिंदु मेमोरी उपयोग नहीं है, लेकिन अगर आप जल्दी से बाहर निकलना चाहते हैं, तो आप पूरे स्ट्रिंग को विभाजित करने के लिए खुद को बचा सकते हैं? (यह आपके विशेष समाधान पर एक टिप्पणी नहीं है, मैं सिर्फ स्मृति के बारे में चर्चा से हैरान था)।
स्कॉट ग्रिफिथ्स

@ सच: एक ऐसे मामले के बारे में सोचना मुश्किल है जहाँ वास्तव में जीत है - जहाँ 1: आप भाग के माध्यम से विभाजन को रोकना चाहते हैं, 2: आप नहीं जानते कि आप अग्रिम में कितने शब्दों को विभाजित कर रहे हैं, 3: आपके पास एक है यह बात करने के लिए पर्याप्त पर्याप्त स्ट्रिंग, और 4: आप लगातार इसे पर्याप्त रूप से रोकते हैं ताकि यह str.split पर एक महत्वपूर्ण जीत हो। यह परिस्थितियों का एक बहुत ही संकीर्ण सेट है।
ग्लेन मेनार्ड

4
यदि आपका तार आलस्य से उत्पन्न होता है (जैसे कि नेटवर्क ट्रैफ़िक या फ़ाइल रीड से) तो आपको बहुत अधिक लाभ हो सकता है
रेयान

3

मैंने @ Ninjagecko के उत्तर का एक संस्करण लिखा है जो string.split (यानी व्हाट्सएप को डिफ़ॉल्ट रूप से सीमांकित करता है और आप एक सीमांकक निर्दिष्ट कर सकते हैं) की तरह व्यवहार करते हैं।

def isplit(string, delimiter = None):
    """Like string.split but returns an iterator (lazy)

    Multiple character delimters are not handled.
    """

    if delimiter is None:
        # Whitespace delimited by default
        delim = r"\s"

    elif len(delimiter) != 1:
        raise ValueError("Can only handle single character delimiters",
                        delimiter)

    else:
        # Escape, incase it's "\", "*" etc.
        delim = re.escape(delimiter)

    return (x.group(0) for x in re.finditer(r"[^{}]+".format(delim), string))

यहाँ मेरे द्वारा इस्तेमाल किए गए परीक्षण हैं (अजगर 3 और अजगर 2 दोनों में):

# Wrapper to make it a list
def helper(*args,  **kwargs):
    return list(isplit(*args, **kwargs))

# Normal delimiters
assert helper("1,2,3", ",") == ["1", "2", "3"]
assert helper("1;2;3,", ";") == ["1", "2", "3,"]
assert helper("1;2 ;3,  ", ";") == ["1", "2 ", "3,  "]

# Whitespace
assert helper("1 2 3") == ["1", "2", "3"]
assert helper("1\t2\t3") == ["1", "2", "3"]
assert helper("1\t2 \t3") == ["1", "2", "3"]
assert helper("1\n2\n3") == ["1", "2", "3"]

# Surrounding whitespace dropped
assert helper(" 1 2  3  ") == ["1", "2", "3"]

# Regex special characters
assert helper(r"1\2\3", "\\") == ["1", "2", "3"]
assert helper(r"1*2*3", "*") == ["1", "2", "3"]

# No multi-char delimiters allowed
try:
    helper(r"1,.2,.3", ",.")
    assert False
except ValueError:
    pass

अजगर के रेगेक्स मॉड्यूल का कहना है कि यह यूनिकोड व्हाट्सएप के लिए "सही काम" करता है , लेकिन मैंने वास्तव में इसे नहीं किया है।

जीस्ट के रूप में भी उपलब्ध है ।


3

यदि आप एक पुनरावृति पढ़ने में सक्षम होना चाहते हैं (साथ ही एक वापसी ) तो यह कोशिश करें:

import itertools as it

def iter_split(string, sep=None):
    sep = sep or ' '
    groups = it.groupby(string, lambda s: s != sep)
    return (''.join(g) for k, g in groups if k)

प्रयोग

>>> list(iter_split(iter("Good evening, world!")))
['Good', 'evening,', 'world!']

3

more_itertools.split_atstr.splitपुनरावृत्तियों के लिए एक एनालॉग प्रदान करता है।

>>> import more_itertools as mit


>>> list(mit.split_at("abcdcba", lambda x: x == "b"))
[['a'], ['c', 'd', 'c'], ['a']]

>>> "abcdcba".split("b")
['a', 'cdc', 'a']

more_itertools एक तृतीय-पक्ष पैकेज है।


1
ध्यान दें कि more_itertools.split_at () अभी भी प्रत्येक कॉल पर एक नई आबंटित सूची का उपयोग कर रहा है, इसलिए जब यह एक पुनरावृत्त लौटाता है, तो यह निरंतर मेमोरी आवश्यकता को प्राप्त नहीं कर रहा है। तो इस बात पर निर्भर करता है कि आप क्यों शुरू करने के लिए एक पुनरावृत्ति चाहते थे, यह सहायक हो सकता है या नहीं।
jcater

@ जेकटर गुड पॉइंट। इसके क्रियान्वयन के अनुसार, मध्यवर्ती मान वास्तव में पुनरावृत्तियों के भीतर उप सूचियों के रूप में बफ़र किए जाते हैं । एक पुनरावृत्तियों के साथ सूचियों को प्रतिस्थापित करने के लिए स्रोत को अनुकूलित कर सकता है, itertools.chainसूची समझ का उपयोग करके परिणामों के साथ संलग्न और मूल्यांकन कर सकता है। आवश्यकता और अनुरोध के आधार पर, मैं एक उदाहरण पोस्ट कर सकता हूं।
17

2

मैं यह दिखाना चाहता था कि दिए गए सीमांकक के लिए एक जनरेटर को वापस करने के लिए find_iter समाधान का उपयोग कैसे करें और फिर पिछले अगले पुनरावृत्ति का निर्माण करने के लिए itertools से युग्मक नुस्खा का उपयोग करें जो मूल विभाजन विधि के अनुसार वास्तविक शब्द प्राप्त करेगा।


from more_itertools import pairwise
import re

string = "dasdha hasud hasuid hsuia dhsuai dhasiu dhaui d"
delimiter = " "
# split according to the given delimiter including segments beginning at the beginning and ending at the end
for prev, curr in pairwise(re.finditer("^|[{0}]+|$".format(delimiter), string)):
    print(string[prev.end(): curr.start()])

ध्यान दें:

  1. मैं प्रचलित और अगले के बजाय prev और वक्र का उपयोग करता हूं क्योंकि अजगर में अगले ओवरराइड करना एक बहुत बुरा विचार है
  2. यह काफी कुशल है

1

डंबेस्ट विधि, रेगेक्स / इटर्टूल के बिना:

def isplit(text, split='\n'):
    while text != '':
        end = text.find(split)

        if end == -1:
            yield text
            text = ''
        else:
            yield text[:end]
            text = text[end + 1:]

0
def split_generator(f,s):
    """
    f is a string, s is the substring we split on.
    This produces a generator rather than a possibly
    memory intensive list. 
    """
    i=0
    j=0
    while j<len(f):
        if i>=len(f):
            yield f[j:]
            j=i
        elif f[i] != s:
            i=i+1
        else:
            yield [f[j:i]]
            j=i+1
            i=i+1

तुम क्यों उपज है [f[j:i]]और नहीं f[j:i]?
मॉबर्ग

0

यहाँ एक सरल प्रतिक्रिया है

def gen_str(some_string, sep):
    j=0
    guard = len(some_string)-1
    for i,s in enumerate(some_string):
        if s == sep:
           yield some_string[j:i]
           j=i+1
        elif i!=guard:
           continue
        else:
           yield some_string[j:]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.