পাইথনে `স্ট্রিং.স্প্লিট () of এর জেনারেটর সংস্করণ রয়েছে?


113

string.split()একটি তালিকা উদাহরণ দেয়। এমন কোনও সংস্করণ রয়েছে যা পরিবর্তে জেনারেটর ফেরত দেয় ? একটি জেনারেটর সংস্করণ থাকার বিরুদ্ধে কোন কারণ আছে?


3
এই প্রশ্নটি সম্পর্কিত হতে পারে।
বিজন পোলাক্স

1
কারণটি হ'ল এটি কার্যকর যে কোনও ক্ষেত্রে চিন্তা করা খুব কঠিন। আপনি এটি কেন চান?
গ্লেন মেইনার্ড

10
@ গ্লেন: সম্প্রতি আমি একটি প্রশ্নের উত্তর দেখতে পেলাম একটি দীর্ঘ স্ট্রিংটিকে এন শব্দের অংশে বিভক্ত করার বিষয়ে। সমাধানগুলির splitমধ্যে একটি স্ট্রিং এবং তারপরে ফলাফলের সাথে কাজ করে একটি জেনারেটর ফিরিয়ে দেয় split। এটি আমাকে ভাবতে splitপেরেছিল যে কোনও জেনারেটর শুরু করার জন্য যদি কোনও উপায় থাকে তবে ।
মনোজ গোবিন্দন

5
পাইথন ইস্যু ট্র্যাকার সম্পর্কিত একটি প্রাসঙ্গিক আলোচনা আছে: বাগস.পিথন.অর্গ
বিএসইউ

@ গ্লেনমায়নার্ড এটি সত্যই বড় বড় বেয়ার স্ট্রিং / ফাইল পার্সিংয়ের জন্য দরকারী হতে পারে তবে যে কেউ জেনারেটর পার্সার লিখতে পারেন স্ব-
ব্রিউড

উত্তর:


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..২.১ এ স্থির স্মৃতি লাগে। আমি খুব বড় আকারের একটি স্ট্রিং তৈরি করেছি (1 গিগাবাইট বা ততোধিক), তারপরে পুনরায় পুনরুক্তকরণের মাধ্যমে একটি forলুপের সাথে পুনরাবৃত্তি করা হবে (কোনও তালিকা বোঝার নয়, যা অতিরিক্ত স্মৃতি তৈরি করবে)। এর ফলে মেমরির লক্ষণীয় বৃদ্ধি পাওয়া যায় নি (এটি যদি স্মৃতিতে বৃদ্ধি থাকে তবে এটি 1 জিবি স্ট্রিংয়ের চেয়ে অনেক কম ছিল)।


5
অসাধারণ! আমি ফাইন্ডারের কথা ভুলে গিয়েছিলাম যদি কেউ স্প্লিটলাইনগুলির মতো কিছু করতে আগ্রহী হয় তবে আমি এই আরই ব্যবহার করার পরামর্শ দেব: '(। * \ N |। + $)' স্ট্রিমস্প্লিটলাইনগুলি ট্রেনিংয়ের নতুন লাইনের বাইরে চলে গেছে (এমন কিছু যা আমি সত্যিই পছন্দ করি না ... ); যদি আপনি আচরণটির সেই অংশটি প্রতিলিপি করতে চান তবে আপনি গ্রুপিং ব্যবহার করতে পারেন: (এম.আর.আর.পি (2) বা এম-ক্রুপ (3) মিটার জন্য রেফাইন্ডারে ('((। *) \ n | (। +)) $) ', s))। PS: আমি অনুমান করি যে আরই মধ্যে বাইরের পেরেন প্রয়োজন হয় না; আমি কেবল ব্যবহার সম্পর্কে অস্বস্তি বোধ করছি
পেরেন

3
পারফরম্যান্স সম্পর্কে কী? পুনরায় মিলে যাওয়া সাধারণ অনুসন্ধানটি ধীর হওয়া উচিত।
অ্যানাটোলি টেকটোনিক

1
আপনি এই স্প্লিট_মিটার ফাংশনটি কীভাবে পুনরায় লিখতে চান a_string.split("delimiter")?
মোবার্গ

বিভাজন যাই হোক না কেন নিয়মিত এক্সপ্রেশন গ্রহণ করে তাই এটি সত্যিই দ্রুত নয়, আপনি যদি পূর্ববর্তী ফ্যাশনে ফেরত মানটি ব্যবহার করতে চান তবে নীচে আমার উত্তরটি দেখুন ...
ভেল্টজার ডোরন

str.split()নিয়মিত প্রকাশগুলি গ্রহণ করে না, এটি re.split()আপনিই
অ্যালেক্সিস

17

পদ্ধতির offsetপরামিতি ব্যবহার করে একটি লিখতে আমি এটি সবচেয়ে কার্যকর উপায়টি ভাবতে পারি str.find()। এটি প্রচুর মেমরির ব্যবহার এড়িয়ে যায় এবং যখন প্রয়োজন হয় না তখন একটি রেজিপ্সকের ওভারহেডের উপর নির্ভর করে।

[2016-8-2 সম্পাদনা করুন: geচ্ছিকভাবে রেজেক্স বিভাজককে সমর্থন করতে এটি আপডেট হয়েছে]

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('][')

সম্পাদনা: কোনও বিভাজক অক্ষর না দেওয়া থাকলে আশেপাশের সাদা স্থানের সঠিক পরিচালনা করা hand


12
কেন এই তুলনায় ভাল re.finditer?
এরিক কাপলুন

@ এরিকক্যাপলুন কারণ আইটেমগুলির জন্য রেজেক্স যুক্তি তাদের বিভাজনকারীদের চেয়ে জটিল হতে পারে। আমার ক্ষেত্রে, আমি প্রতিটি লাইন পৃথকভাবে প্রক্রিয়া করতে চেয়েছিলাম, তাই কোনও লাইন মেলতে ব্যর্থ হলে আমি আবার রিপোর্ট করতে পারি।
রোভিকো

9

প্রস্তাবিত বিভিন্ন পদ্ধতিতে কিছু পারফরম্যান্স টেস্টিং করেছে (আমি তাদের এখানে পুনরাবৃত্তি করব না)। কিছু ফলাফল:

  • str.split (ডিফল্ট = 0.3461570239996945
  • ম্যানুয়াল অনুসন্ধান (চরিত্র অনুসারে) (ডেভ ওয়েবের উত্তরগুলির মধ্যে একটি) = 0.8260340550004912
  • re.finditer (নিনজেকেকোর উত্তর) = 0.698872097000276
  • str.find (এলি কলিন্সের উত্তরগুলির মধ্যে একটি) = 0.7230395330007013
  • itertools.takewhile (ইগনাসিও ওয়াজকেজ-আব্রামের উত্তর) = 2.023023967998597
  • str.split(..., maxsplit=1) পুনরাবৃত্তি = এন / এ †

† পুনরাবৃত্তির উত্তরগুলি ( 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

এখানে আমার বাস্তবায়ন, যা এখানে অন্যান্য উত্তরগুলির চেয়ে অনেক বেশি, দ্রুত এবং আরও সম্পূর্ণ complete বিভিন্ন ক্ষেত্রে এটির জন্য 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
Ignacio Vazquez-Abram

বিভাজকের একাধিক অক্ষর থাকতে পারে'abc<def<>ghi<><>lmn'.split('<>') == ['abc<def', 'ghi', '', 'lmn']
কেনেটিএম

@ ইগনাসিও: আপনি কি নিজের উত্তরের একটি উদাহরণ যোগ করতে পারেন?
মনোজ গোবিন্দন

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: স্ট্রিংস্প্লিটের উপর এটি একটি গুরুত্বপূর্ণ জয় হওয়ার জন্য আপনি ধারাবাহিকভাবে পর্যাপ্ত পর্যায়ে থামান। এটি শর্তগুলির একটি খুব সংকীর্ণ সেট।
গ্লেন মেইনার্ড

4
আপনার স্ট্রিংটিও অলসভাবে উত্পন্ন হলে (যেমন নেটওয়ার্ক ট্র্যাফিক বা ফাইল রিডিং থেকে) তৈরি করা যেতে পারে
লিয় রায়ান

3

আমি @ নিনজেকেকোর জবাবের একটি সংস্করণ লিখেছি যা আরও বেশি স্ট্রিং.স্প্লিটের মতো আচরণ করে (যেমন ডিফল্টরূপে সাদা বর্ণমালা নির্ধারণ করা হয় এবং আপনি একটি সীমানা নির্দিষ্ট করতে পারেন)।

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
নোট করুন যে আরও_জিরিটোস.স্প্লিট_এট () প্রতিটি কলটিতে এখনও একটি নতুন বরাদ্দকৃত তালিকা ব্যবহার করছে, সুতরাং এটি যখন কোনও পুনরাবৃত্তিকে ফিরিয়ে দেয়, এটি ধ্রুবক মেমরির প্রয়োজনীয়তা অর্জন করে না। সুতরাং আপনি কেন পুনরুক্তি করতে চেয়েছিলেন তার উপর নির্ভর করে এটি সহায়ক হতে পারে বা নাও হতে পারে।
জ্যাকটার 13

@ জ্যাকটার ভাল পয়েন্ট। মধ্যবর্তী মানগুলি প্রকৃতপক্ষে এর প্রয়োগ অনুসারে পুনরুক্তরের মধ্যে উপ-তালিকা হিসাবে বাফার হয় । কেউ পুনরুক্তিকারীদের সাথে তালিকার বিকল্পগুলি উত্সকে অভিযোজিত করতে পারে, itertools.chainতালিকা অনুধাবন করে ফলাফলগুলি সংযোজন এবং মূল্যায়ন করতে পারে। প্রয়োজন এবং অনুরোধের উপর নির্ভর করে আমি একটি উদাহরণ পোস্ট করতে পারি।
পাইং

2

আমি কীভাবে সন্ধান করতে চাই যে প্রদত্ত বিতরণকারীদের জন্য জেনারেটর ফিরিয়ে আনতে ফাইন্ডিটার সলিউশনটি ব্যবহার করতে হবে এবং তারপরে পূর্ববর্তী পুনরাবৃত্তিটি তৈরি করতে ইতরটোলগুলি থেকে পেয়ারওয়াই রেসিপিটি ব্যবহার করুন যা আসল শব্দগুলি আসল বিভাজন পদ্ধতি হিসাবে পাওয়া যাবে।


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. আমি পূর্ব ও পরবর্তীগুলির পরিবর্তে পূর্ব ও করর ব্যবহার করি কারণ পাইথনের পরবর্তী ওভাররাইড করা খুব খারাপ ধারণা
  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:]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.