我想使用-
,+=
,==
,=
,+
和空格作为分隔符来拆分字符串。我想保留分隔符,除非它是空格。
我尝试使用以下代码实现此目的:
def tokenize(s):
import re
pattern = re.compile("(\-|\+\=|\=\=|\=|\+)|\s+")
return pattern.split(s)
print(tokenize("hello-+==== =+ there"))
我预计输出为
['hello', '-', '+=', '==', '=', '=', '+', 'there']
但是我得到了
['hello', '-', '', '+=', '', '==', '', '=', '', None, '', '=', '', '+', '', None, 'there']
这几乎是我想要的,除了有很多无关的None
和空字符串。
为什么它会以这种方式运行,我怎样才能改变它以获得我想要的东西?
答案 0 :(得分:3)
re.split默认返回匹配之间的字符串位数组:(如@Laurence Gonsalves所说,这是它的主要用途。)
['hello', '', '', '', '', '', '', '', 'there']
请注意-
和+=
,+=
和==
之间的空字符串等。
正如文档所解释的那样,因为您正在使用捕获组(即,因为您使用的是(\-|\+\=|\=\=|\=|\+)
而不是(?:\-|\+\=|\=\=|\=|\+)
,所以捕获组匹配的位是散布的:
['hello', '-', '', '+=', '', '==', '', '=', '', None, '', '=', '', '+', '', None, 'there']
None
对应于您的模式的\s+
一半匹配的位置;在那些情况下,捕获组没有捕获任何东西。
从查看re.split的文档,我看不到一种简单的方法让它在匹配之间丢弃空字符串,尽管简单的列表理解(或filter,如果你愿意)可以很容易丢弃None
和空字符串:
def tokenize(s):
import re
pattern = re.compile("(\-|\+\=|\=\=|\=|\+)|\s+")
return [ x for x in pattern.split(s) if x ]
最后一个注释:对于您到目前为止所描述的内容,这样可以正常工作,但根据项目的方向,您可能需要切换到正确的解析库。 The Python wiki对这里的一些选项有很好的概述。
答案 1 :(得分:2)
为什么会这样?
根据re.split的文档:
如果在模式中使用捕获括号,则模式中所有组的文本也将作为结果列表的一部分返回。
这是完全正确的:如果使用捕获括号,则返回所有组的文本,无论它们是否匹配任何内容;那些不匹配的东西会返回None
。
与split
一样,两个连续的分隔符被认为是分隔空字符串,因此你会散布空字符串。
如何更改它以获得我想要的内容?
最简单的解决方案是过滤输出:
filter(None, pattern.split(s))
答案 2 :(得分:2)
或许re.findall
更适合你?
>>> re.findall(r'-|\+=|==|=|\+|[^-+=\s]+', "hello-+==== =+ there")
['hello', '-', '+=', '==', '=', '=', '+', 'there']
答案 3 :(得分:1)
此模式更符合您的要求:
\s*(\-|\+\=|\=\=|\=|\+)\s*
但是,您仍然会在每次拆分之间获得一个空字符串,正如您所期望的那样。
答案 4 :(得分:0)
试试这个:
def tokenize(s):
import re
pattern = re.compile("(\-|\+\=|\=\=|\=|\+)|\s+")
x = pattern.split(s)
result = []
for item in x:
if item != '' and item != None:
result.append(item)
return result
print(tokenize("hello-+==== =+ there"))