re.split('\W', 'foo/bar spam\neggs')
-> ['foo', 'bar', 'spam', 'eggs']
这就是我想要的:
someMethod('\W', 'foo/bar spam\neggs')
-> ['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs']
原因是我想将字符串拆分为标记,对其进行操作,然后将其重新放回原处。
#1 楼
>>> re.split('(\W)', 'foo/bar spam\neggs')
['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs']
评论
这很酷。我不知道re.split是否对捕获组做到了这一点。
–劳伦斯·贡萨尔维斯(Laurence Gonsalves)
2010-1-25在23:48
@Laurence:嗯,有文档记录:docs.python.org/library/re.html#re.split:“按模式的出现将字符串分割开。如果在模式中使用捕获括号,则模式中所有组的文本也会作为结果列表的一部分返回。”
– Vinay Sajip
2010-1-25在23:54
记录严重不足。我已经使用Python 14年了,才发现这一点。
–smci
13年6月19日在16:33
是否有一个选项可以使组匹配的输出附加到拆分左侧(或类似右侧)的内容?例如,可以方便地对其进行修改,使输出为['foo','/ bar','spam','\ neggs']吗?
– ely
2015年2月9日在2:24
@ Mr.F您也许可以对re.sub做一些事情。我想分割结尾的百分比,所以我只是将其加进一个双字符,然后分割,但有点怪,但适合我的情况:re.split('%',re.sub('%','%%','5.000 %Additional Whatnot'))-> ['5.000%','Additional Whatnot']
–凯尔·詹姆斯·沃克(Kyle James Walker)
2015年10月11日在22:41
#2 楼
如果要在换行符上拆分,请使用splitlines(True)
。 br />#3 楼
另一个示例,对非字母数字进行拆分并保留分隔符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
18-10-17在1:03
我也喜欢它的可读性,如果您要包含/排除一些字符,可以自定义它!
–tikka
12月11日15:04
#4 楼
另一个在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, '<'))
#5 楼
如果只有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
评论
您还可以添加if x,以确保split生成的块具有某些内容,即result = [x + text.split(sep)中x的sep如果x]
–我震惊了外星人
5月8日15:12
对我来说,去除太多了,我不得不使用:result = [sep + x for data.split(sep)中的x] result [0] = result [0] [len(sep):]
– Scottyttle
6月10日0:49
#6 楼
# 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']
#7 楼
一个懒惰和简单的解决方案假设您的正则表达式模式是
split_pattern = r'(!|\?)'
首先,您添加与新分隔符相同的字符,例如'[cut]'
new_string = re.sub(split_pattern, '\1[cut]', your_string)
然后拆分新的分隔符
new_string.split('[cut]')
评论
这种方法很聪明,但是当原始字符串已经在某处包含[cut]时,它将失败。
–Matthijs Kooijman
19-09-19在9:27
在大型问题上,它可能会更快,因为它最终使用string.split(),以防re.split()的花费比带有string.split()的re.sub()花费更多(我不知道)。
–洛伦茨
6月26日12:43
#8 楼
您还可以使用字符串数组而不是正则表达式来拆分字符串,如下所示:def tokenizeString(aString, separators):
#separators is an array of strings that are being used to split 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 = ["'''", '+=', '+', "/", "*", "\'", '\"', "-=", "-", " ", '"""', "(", ")"]))
#9 楼
这是一个简单的.split
解决方案,不需要regex。这是Python 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 _ in range(100000): length = random.randint(1, 50) s = "".join(random.choice(CHARS) for _ in range(length)) assert "".join(splitkeep(s, delimiter)) == s
pre >评论
出于速度原因,应避免在大型问题上使用正则表达式,这就是一个很好的提示。
–洛伦茨
6月26日12:40
#10 楼
如果要分割字符串同时用正则表达式保留分隔符而不捕获组: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)
两种方法都将删除在大多数情况下无用且烦人的空组。
#11 楼
将所有
seperator: (\W)
替换为seperator + new_seperator: (\W;)
由
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')
#12 楼
我在尝试拆分文件路径时遇到了类似的问题,并且很难找到一个简单的答案。my_path = 'folder1/folder2/folder3/file1'
import re
re.findall('[^/]+/|[^/]+', my_path)
返回值:
['folder1/', 'folder2/', 'folder3/', 'file1']
评论
可以使用以下方法稍微简化一下:re.findall('[^ /] + /?',my_path)(例如,使用?使尾部斜杠为可选,而不是使用|来提供两个替代项。
–Matthijs Kooijman
19年9月19日在9:30
对于路径,最好使用stdlib os.path函数
–anon01
8月21日6:31
#13 楼
我发现这种基于生成器的方法更加令人满意: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:]
它避免了找出正确的正则表达式的需要,而理论上应该是相当便宜的。它不会创建新的字符串对象,而是将大部分迭代工作委托给高效的find方法。
def split_keep(string, sep):
start = 0
while (end := string.find(sep, start) + 1) > 0:
yield string[start:end]
start = end
yield string[start:]
评论
\ W代表什么?我在Google上失败了。非文字字符,请参见此处了解详情
有关应用于原始字节字符串的问题,请放到“拆分字符串并将分隔符保留为拆分字符串块的一部分,而不是作为单独的列表元素”,请参阅stackoverflow.com/questions/62591863/…