我有一个这样的字符串:

this is "a test"

我试图在Python中写一些东西,通过空格分割它,同时忽略引号中的空格。我想要的结果是:

['this', 'is', 'a test']

PS,我知道你会问“如果引号中有引号会发生什么,在我的应用程序中,这永远不会发生。


当前回答

由于性能原因,re似乎更快。下面是我的解决方案,使用最小贪婪操作符,保留外部引号:

re.findall("(?:\".*?\"|\S)+", s)

结果:

['this', 'is', '"a test"']

它将像aaa“bla blub”bbb这样的结构放在一起,因为这些标记没有被空格分隔。如果字符串包含转义字符,你可以这样匹配:

>>> a = "She said \"He said, \\\"My name is Mark.\\\"\""
>>> a
'She said "He said, \\"My name is Mark.\\""'
>>> for i in re.findall("(?:\".*?[^\\\\]\"|\S)+", a): print(i)
...
She
said
"He said, \"My name is Mark.\""

请注意,这也通过模式的\S部分来匹配空字符串“”。

其他回答

嗯,好像找不到“回复”按钮了…不管怎样,这个答案是基于Kate的方法,但正确地分割了包含转义引号的子字符串,并删除了子字符串的开始和结束引号:

  [i.strip('"').strip("'") for i in re.split(r'(\s+|(?<!\\)".*?(?<!\\)"|(?<!\\)\'.*?(?<!\\)\')', string) if i.strip()]

这适用于'这是' a \\\"test\\\"\\\'s子字符串' '这样的字符串(不幸的是,为了防止Python删除转义,这个疯狂的标记是必要的)。

如果返回列表中的字符串不需要转义,您可以使用稍微修改过的函数版本:

[i.strip('"').strip("'").decode('string_escape') for i in re.split(r'(\s+|(?<!\\)".*?(?<!\\)"|(?<!\\)\'.*?(?<!\\)\')', string) if i.strip()]

根据你的用例,你可能还想检查csv模块:

import csv
lines = ['this is "a string"', 'and more "stuff"']
for row in csv.reader(lines, delimiter=" "):
    print(row)

输出:

['this', 'is', 'a string']
['and', 'more', 'stuff']

要解决某些Python 2版本中的unicode问题,我建议:

from shlex import split as _split
split = lambda a: [b.decode('utf-8') for b in _split(a.encode('utf-8'))]

我用shlex。拆分来处理七千万行鱿鱼日志,太慢了。所以我换成了re。

请尝试这个,如果你有性能问题与shlex。

import re

def line_split(line):
    return re.findall(r'[^"\s]\S*|".+?"', line)

你需要从内置的shlex模块中分离。

>>> import shlex
>>> shlex.split('this is "a test"')
['this', 'is', 'a test']

这应该是你想要的效果。

如果你想保留引号,那么你可以传递posix=False kwarg。

>>> shlex.split('this is "a test"', posix=False)
['this', 'is', '"a test"']