wake-up-neo.com

Wie kann ich in Python eine Zeichenfolge aufteilen und die Trennzeichen beibehalten?

Hier ist der einfachste Weg, dies zu erklären. Hier ist was ich verwende:

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

Hier ist was ich will:

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

Der Grund ist, dass ich einen String in Token aufteilen, bearbeiten und wieder zusammenfügen möchte.

151
Ken Kinder
>>> re.split('(\W)', 'foo/bar spam\neggs')
['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs']
204

Wenn Sie in Newline aufteilen, verwenden Sie splitlines(True) .

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

(Keine generelle Lösung, aber hier hinzufügen, falls jemand hierher kommt und diese Methode nicht kennt.)

17
Mark Lodato

Eine weitere No-Regex-Lösung, die auf Python 3 gut funktioniert

# 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, '<'))
9
ootwch

Wenn Sie nur ein Trennzeichen haben, können Sie Listenverständnisse verwenden:

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

Trennzeichen anhängen/voranstellen:

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']

Trennzeichen als eigenes Element:

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
5
Granitosaurus

ein anderes Beispiel ist die Aufteilung in nicht alphanumerische Zeichen und die Trennzeichen

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

ausgabe:

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

erläuterung

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

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

Sie können einen String auch mit einem Array von Strings anstelle eines regulären Ausdrucks aufteilen.

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
Anderson Green
# 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
Moisey Oysgelt

Wenn Sie die Zeichenfolge unter Beibehaltung der Trennzeichen durch Regex teilen möchten, ohne die Gruppe zu erfassen:

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)

Wenn man davon ausgeht, dass Regex in Capturing-Gruppe eingeschlossen ist:

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)

Beide Methoden werden auch leere Gruppen entfernen, die in den meisten Fällen nutzlos und ärgerlich sind.

1
Dmitriy Sintsov

Eine faule und einfache Lösung

Angenommen, Ihr Regex-Muster ist split_pattern = r'(!|\?)'

Zunächst fügen Sie dasselbe Zeichen wie das neue Trennzeichen hinzu, z. B. "[Ausschneiden]".

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

Dann teilen Sie das neue Trennzeichen new_string.split('[cut]')

1
Yilei Wang

Ich hatte ein ähnliches Problem beim Versuch, einen Dateipfad aufzuteilen, und hatte Mühe, eine einfache Antwort zu finden. Dies hat bei mir funktioniert und es war nicht erforderlich, Trennzeichen in den geteilten Text zurückzusetzen:

my_path = 'folder1/folder2/folder3/file1'

import re

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

kehrt zurück:

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

0
Conor