В Python, как мне разделить строку и сохранить разделители?
вот самый простой способ объяснить это. Вот что я использую:
re.split('W', 'foo/bar spamneggs')
-> ['foo', 'bar', 'spam', 'eggs']
вот что я хочу:
someMethod('W', 'foo/bar spamneggs')
-> ['foo', '/', 'bar', ' ', 'spam', 'n', 'eggs']
причина в том, что я хочу разделить строку на токены, манипулировать ею, а затем снова собрать ее вместе.
9 ответов:
Если вы разделяете на новой строке, используйте
splitlines(True).>>> 'line 1\nline 2\nline without newline'.splitlines(True) ['line 1\n', 'line 2\n', 'line without newline'](не общее решение, но добавление этого здесь, Если кто-то приходит сюда, не понимая, что этот метод существует.)
еще одно решение без регулярных выражений, которое хорошо работает на Python 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, '<'))
Если у вас есть только 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
вы также можете разделить строку с массивом строк вместо регулярного выражения, например:
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 = ["'''", '+=', '+', "/", "*", "\'", '\"', "-=", "-", " ", '"""', "(", ")"]))
# 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']
Если вы хотите разделить строку, сохраняя разделители регулярным выражением без захвата группы:
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)обе стороны также удалить пустые группы, которые бесполезны и раздражают в большинстве случаев.
другой пример, разделить на не буквенно-цифровой и сохранить разделители
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.
одно ленивое и простое решение
предположим, что ваш шаблон регулярных выражений
split_pattern = r'(!|\?)'во-первых, вы добавляете тот же символ, что и новый разделитель, например '[cut]'
new_string = re.sub(split_pattern, '\1[cut]', your_string)затем вы разделяете новый разделитель,
new_string.split('[cut]')
Comments