পাইথনে, আমি কীভাবে একটি স্ট্রিং বিভক্ত করব এবং বিভাজক রাখব?


226

এটি ব্যাখ্যা করার সহজ উপায় এখানে। আমি যা ব্যবহার করছি তা এখানে:

re.split('\W', 'foo/bar spam\neggs')
-> ['foo', 'bar', 'spam', 'eggs']

আমি যা চাই তা এখানে:

someMethod('\W', 'foo/bar spam\neggs')
-> ['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs']

কারণটি হ'ল আমি একটি স্ট্রিং টোকনে বিভক্ত করতে চাইছি, এটিকে ম্যানিপুলেট করব এবং তারপরে আবার একসাথে রেখে দিতে চাই put


3
কি \Wজন্য দাঁড়ানো? আমি গুগল এ ব্যর্থ।
ওকার

7
একটি শব্দহীন চরিত্র বিশদের জন্য এখানে দেখুন
রাসেল

উত্তর:


295
>>> re.split('(\W)', 'foo/bar spam\neggs')
['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs']

22
চমৎকার. আমি জানতাম না রিপ্লিট ক্যাপচার গ্রুপগুলির সাথে এটি করেছে।
লরেন্স গনসাল্ভেস

16
@ লরেন্স: আচ্ছা, এটি নথিভুক্ত করা হয়েছে: ডকস.পিথন.আর.লাইবারি / রিস্মিচটিএমটিল স্প্রে : "প্যাটার্নের উপস্থিতি অনুসারে স্ট্রিট বিভক্ত করুন parent ফলাফলের তালিকার অংশ হিসাবেও ফেরত দেওয়া হয়েছে। "
বিনয় সাজিপ

40
এটি গুরুতরভাবে আন্ডার-ডকুমেন্টেড। আমি পাইথনটি 14 বছর ধরে ব্যবহার করছি এবং কেবল এটি সন্ধান করেছি।
স্মি

19
গ্রুপের ম্যাচের আউটপুটটি বিভাজনের বামে (বা আনুষাঙ্গিকভাবে ডানদিকে) যা আছে তার সাথে সংযুক্ত আছে কি এমন কোনও বিকল্প আছে? উদাহরণস্বরূপ, আউটপুট তাই এটি সহজেই পরিবর্তন করা যেতে পারে ['foo', '/bar', ' spam', '\neggs']?
ely

3
@ মিঃ এফ আপনি রি.সউব দিয়ে কিছু করতে সক্ষম হতে পারেন। আমি একটি শেষ শতাংশে বিভক্ত করতে চেয়েছিলাম তাই আমি কেবল একটি ডাবল চরিত্রে ডুবে গেলাম এবং তারপরে বিভক্ত হয়ে গেলাম, তবে আমার ক্ষেত্রে কাজ করেছে: re.split('% ', re.sub('% ', '%% ', '5.000% Additional Whatnot'))->['5.000%', 'Additional Whatnot']
কাইল জেমস ওয়াকার

29

আপনি যদি নতুন লাইনে বিভক্ত হয়ে থাকেন তবে ব্যবহার করুন splitlines(True)

>>> 'line 1\nline 2\nline without newline'.splitlines(True)
['line 1\n', 'line 2\n', 'line without newline']

(কোনও সাধারণ সমাধান নয়, তবে কেউ যদি এই পদ্ধতিটির অস্তিত্ব না বুঝতে পারে তবে এখানে এটি যুক্ত করুন))


12

পাইথন 3-তে ভালভাবে কাজ করে এমন একটি নো-রেজেক্স সমাধান

# Split strings and keep separator
test_strings = ['<Hello>', 'Hi', '<Hi> <Planet>', '<', '']

def split_and_keep(s, sep):
   if not s: return [''] # consistent with string.split()

   # Find replacement character that is not used in string
   # i.e. just use the highest available character plus one
   # Note: This fails if ord(max(s)) = 0x10FFFF (ValueError)
   p=chr(ord(max(s))+1) 

   return s.replace(sep, sep+p).split(p)

for s in test_strings:
   print(split_and_keep(s, '<'))


# If the unicode limit is reached it will fail explicitly
unicode_max_char = chr(1114111)
ridiculous_string = '<Hello>'+unicode_max_char+'<World>'
print(split_and_keep(ridiculous_string, '<'))

10

আপনার যদি কেবল 1 বিভাজক থাকে তবে আপনি তালিকা বোধের নিয়োগ করতে পারেন:

text = 'foo,bar,baz,qux'  
sep = ','

বিভাজক সংযোজন / প্রিপেন্ডিং:

result = [x+sep for x in text.split(sep)]
#['foo,', 'bar,', 'baz,', 'qux,']
# to get rid of trailing
result[-1] = result[-1].strip(sep)
#['foo,', 'bar,', 'baz,', 'qux']

result = [sep+x for x in text.split(sep)]
#[',foo', ',bar', ',baz', ',qux']
# to get rid of trailing
result[0] = result[0].strip(sep)
#['foo', ',bar', ',baz', ',qux']

এটি নিজস্ব উপাদান হিসাবে পৃথককারী:

result = [u for x in text.split(sep) for u in (x, sep)]
#['foo', ',', 'bar', ',', 'baz', ',', 'qux', ',']
results = result[:-1]   # to get rid of trailing

1
আপনি এটি if xনিশ্চিত করতে যোগ করতে পারেন যে উত্পাদিত অংশটির splitকিছু বিষয়বস্তু রয়েছে, যেমনresult = [x + sep for x in text.split(sep) if x]
আমি এলিয়েন

আমার জন্য, স্ট্রিপটি খুব বেশি সরিয়েছে এবং আমাকে এটি ব্যবহার করতে হয়েছিল:result = [sep+x for x in data.split(sep)] result[0] = result[0][len(sep):]
স্কটলিটল

9

অন্য একটি উদাহরণ, অ-আলফা-সংখ্যায় বিভক্ত করুন এবং বিভাজকগুলি রাখুন

import re
a = "foo,bar@candy*ice%cream"
re.split('([^a-zA-Z0-9])',a)

আউটপুট:

['foo', ',', 'bar', '@', 'candy', '*', 'ice', '%', 'cream']

ব্যাখ্যা

re.split('([^a-zA-Z0-9])',a)

() <- keep the separators
[] <- match everything in between
^a-zA-Z0-9 <-except alphabets, upper/lower and numbers.

ডকস যেমন বলেছেন, এটি গৃহীত উত্তরের সমান, তবে আমি এই সংস্করণটির পঠনযোগ্যতা পছন্দ করি - যদিও \Wএটি প্রকাশের আরও কমপ্যাক্ট উপায়।
ephsmith

3

আপনি নিয়মিত প্রকাশের পরিবর্তে স্ট্রিংগুলির একটি অ্যারে দিয়ে একটি স্ট্রিং বিভক্ত করতে পারেন:

def tokenizeString(aString, separators):
    #separators is an array of strings that are being used to split the the string.
    #sort separators in order of descending length
    separators.sort(key=len)
    listToReturn = []
    i = 0
    while i < len(aString):
        theSeparator = ""
        for current in separators:
            if current == aString[i:i+len(current)]:
                theSeparator = current
        if theSeparator != "":
            listToReturn += [theSeparator]
            i = i + len(theSeparator)
        else:
            if listToReturn == []:
                listToReturn = [""]
            if(listToReturn[-1] in separators):
                listToReturn += [""]
            listToReturn[-1] += aString[i]
            i += 1
    return listToReturn


print(tokenizeString(aString = "\"\"\"hi\"\"\" hello + world += (1*2+3/5) '''hi'''", separators = ["'''", '+=', '+', "/", "*", "\\'", '\\"', "-=", "-", " ", '"""', "(", ")"]))

3
# This keeps all separators  in result 
##########################################################################
import re
st="%%(c+dd+e+f-1523)%%7"
sh=re.compile('[\+\-//\*\<\>\%\(\)]')

def splitStringFull(sh, st):
   ls=sh.split(st)
   lo=[]
   start=0
   for l in ls:
     if not l : continue
     k=st.find(l)
     llen=len(l)
     if k> start:
       tmp= st[start:k]
       lo.append(tmp)
       lo.append(l)
       start = k + llen
     else:
       lo.append(l)
       start =llen
   return lo
  #############################

li= splitStringFull(sh , st)
['%%(', 'c', '+', 'dd', '+', 'e', '+', 'f', '-', '1523', ')%%', '7']

2

একটি অলস এবং সরল সমাধান

ধরুন আপনার রেজেক্স প্যাটার্নটি split_pattern = r'(!|\?)'

প্রথমে আপনি নতুন বিভাজকের মতো '[কাট]' এর মতো কিছু চরিত্র যুক্ত করবেন

new_string = re.sub(split_pattern, '\\1[cut]', your_string)

তারপরে আপনি নতুন বিভাজককে বিভক্ত করুন, new_string.split('[cut]')


এই পদ্ধতিরটি চতুর, তবে ব্যর্থ হবে যখন মূল স্ট্রিংটিতে ইতিমধ্যে [cut]কোথাও রয়েছে ।
ম্যাথিজস কুইজমান

1

যদি কেউ ক্যাপচার না করে রেজেক্স দ্বারা বিভাজক রেখে স্ট্রিং বিভক্ত করতে চায়:

def finditer_with_separators(regex, s):
    matches = []
    prev_end = 0
    for match in regex.finditer(s):
        match_start = match.start()
        if (prev_end != 0 or match_start > 0) and match_start != prev_end:
            matches.append(s[prev_end:match.start()])
        matches.append(match.group())
        prev_end = match.end()
    if prev_end < len(s):
        matches.append(s[prev_end:])
    return matches

regex = re.compile(r"[\(\)]")
matches = finditer_with_separators(regex, s)

যদি কেউ ধরে নেয় যে রেজেক্স ক্যাপচারিং গ্রুপে জড়িয়ে পড়েছে:

def split_with_separators(regex, s):
    matches = list(filter(None, regex.split(s)))
    return matches

regex = re.compile(r"([\(\)])")
matches = split_with_separators(regex, s)

উভয় উপায়ই খালি গোষ্ঠীগুলি সরিয়ে ফেলবে যা বেশিরভাগ ক্ষেত্রে অকেজো এবং বিরক্তিকর।


0

আমি একটি ফাইল পাথ বিভক্ত করার চেষ্টা করে একই রকম সমস্যা পেয়েছি এবং একটি সহজ উত্তর খুঁজতে লড়াই করেছি। এটি আমার পক্ষে কাজ করেছে এবং বিভাজিত পাঠ্যে ফেরত পাঠকদের বিকল্প হিসাবে অন্তর্ভুক্ত করবে না:

my_path = 'folder1/folder2/folder3/file1'

import re

re.findall('[^/]+/|[^/]+', my_path)

আয়:

['folder1/', 'folder2/', 'folder3/', 'file1']


এই সামান্য ব্যবহার করে সরলীকৃত করা যেতে পারে re.findall('[^/]+/?', my_path)(যেমন একটি ব্যবহার ঐচ্ছিক trailing স্ল্যাশ উপার্জন ?বদলে দুটি বিকল্প প্রদান |
Matthijs Kooijman

0

আমি এই জেনারেটর ভিত্তিক পদ্ধতিকে আরও সন্তোষজনক বলে মনে করেছি:

def split_keep(string, sep):
    """Usage:
    >>> list(split_keep("a.b.c.d", "."))
    ['a.', 'b.', 'c.', 'd']
    """
    start = 0
    while True:
        end = string.find(sep, start) + 1
        if end == 0:
            break
        yield string[start:end]
        start = end
    yield string[start:]

এটি সঠিক রেগেক্স বের করার প্রয়োজনীয়তা এড়ায়, তত্ত্ব অনুসারে মোটামুটি সস্তা হওয়া উচিত। এটি নতুন স্ট্রিং অবজেক্ট তৈরি করে না এবং বেশিরভাগ পুনরাবৃত্তির কাজকে দক্ষ অনুসন্ধান পদ্ধতিতে প্রতিনিধিত্ব করে।

... এবং পাইথন 3.8 এ এটি যতটা সংক্ষিপ্ত হতে পারে:

def split_keep(string, sep):
    start = 0
    while (end := string.find(sep, start) + 1) > 0:
        yield string[start:end]
        start = end
    yield string[start:]

0
  1. seperator: (\W)সঙ্গে সব প্রতিস্থাপনseperator + new_seperator: (\W;)

  2. দ্বারা বিভক্ত new_seperator: (;)

def split_and_keep(seperator, s):
  return re.split(';', re.sub(seperator, lambda match: match.group() + ';', s))

print('\W', 'foo/bar spam\neggs')

0

এখানে একটি সহজ .splitসমাধান যা রেইগেক্স ছাড়াই কাজ করে।

এটি ডিলিমিটারটি সরিয়ে না ফেলে পাইথন বিভাজনের () একটি উত্তর , সুতরাং মূল পোস্টটি যা জিজ্ঞাসা করে ঠিক তা নয় তবে অন্যান্য প্রশ্নের উত্তরটির এটির নকল হিসাবে বন্ধ করা হয়েছিল।

def splitkeep(s, delimiter):
    split = s.split(delimiter)
    return [substr + delimiter for substr in split[:-1]] + [split[-1]]

এলোমেলো পরীক্ষা:

import random

CHARS = [".", "a", "b", "c"]
assert splitkeep("", "X") == [""]  # 0 length test
for delimiter in ('.', '..'):
    for idx in range(100000):
        length = random.randint(1, 50)
        s = "".join(random.choice(CHARS) for _ in range(length))
        assert "".join(splitkeep(s, delimiter)) == s
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.