Python中除了引号中的空格外,按空格拆分字符串,但保留引号

3
我想要将以下字符串拆分:
Quantity [*,'EXTRA 05',*]
期望的结果是:
["Quantity", "[*,'EXTRA 05',*]"]
我发现最接近的方法是使用 shlex.split,但是这会删除内部的引号,从而得到以下结果:
['Quantity', '[*,EXTRA 05,*]']
如有其他建议,敬请赐教。
编辑:
还需要进行多个拆分,例如:
"Quantity [*,'EXTRA 05',*] [*,'EXTRA 09',*]"
转换为:
["Quantity", "[*,'EXTRA 05',*]", "[*,'EXTRA 09',*]"]

也许你可以尝试使用正则表达式,通过生成器函数或循环逐个捕获要分离的部分。如果我说得不清楚,抱歉,我没有更多时间解释。但如果你知道我在说什么,这种方法可能有效。 - Totem
你好。第一个字符总是“数量”这个词吗?或者至少在列表的表示之前有一个唯一的单词吗?列表的表示总是作为尾随字符出现吗?字符串中是否有可能出现类似于“[,'EXTRA [bonus] 05',]”或“[,'EXTRA; bonus] 05',]”或“[,'EXTRA [bonus [05',]”这样的序列,也就是列表表示中嵌套的括号? - eyquem
你是在寻找一个针对标题中所提出问题的通用解决方案,还是一个特定于看起来非常类似于你所给出示例字符串的解决方案? - Jack Aidley
4个回答

4

处理字符串的基本方法是使用正则表达式工具 ( 模块 re )。

根据您提供的信息(这意味着它们可能不足够),以下代码可以完成任务:

import re

r = re.compile('(?! )[^[]+?(?= *\[)'
               '|'
               '\[.+?\]')


s1 = "Quantity [*,'EXTRA 05',*] [*,'EXTRA 09',*]"
print r.findall(s1)
print '---------------'      

s2 = "'zug hug'Quantity boondoggle 'fish face monkey "\
     "dung' [*,'EXTRA 05',*] [*,'EXTRA 09',*]"
print r.findall(s2)

结果

['Quantity', "[*,'EXTRA 05',*]", "[*,'EXTRA 09',*]"]  
---------------
["'zug hug'Quantity boondoggle 'fish face monkey dung'", "[*,'EXTRA 05',*]", "[*,'EXTRA 09',*]"]

正则表达式模式必须按以下方式理解:
“|”表示或。
因此,正则表达式模式表示两个部分RE: (?!)[^[]+?= * \ [)和\ [.+?\]
第一个部分RE:
核心是[^[]+。 括号定义一组字符。符号^在第一个括号[后面,它的意思是将该集合定义为不是跟随符号^的那些字符的所有字符。 目前,[^[]意味着任何不是开放括号[的字符,并且由于在此集合的定义之后有+,所以[^[]+表示其中没有括号的字符序列。 现在,在[^[]+后面有一个问号:它意味着捕获的序列必须在问号后面的符号中停止。 这里,问号后面的是?= *\ [,它是一个前瞻断言,由?=…组成,表示它是一个积极的前瞻断言,由* \ [组成,这是捕获的序列必须停止的序列。 *\[表示:零、一个或多个空格直到开放括号(需要反斜杠\来消除[作为字符集开放的含义)。 核心前面也有(!),这是一个负向前瞻断言:必须使此部分RE仅捕获以空格开头的序列,从而避免捕获空格的连续。 删除此(!)并查看效果。
第二部分RE:
\[.+?\]表示:开放括号字符[,一个由。+?捕获的字符序列(点与任何字符匹配,除了\n),这个序列必须在结束括号字符]前停止,这是最后一个要捕获的字符。

string = "Quantity [*,'EXTRA 05',*] [*,'EXTRA 09',*]"
import re
print re.split(' (?=\[)',string)

结果

['Quantity', "[*,'EXTRA 05',*]", "[*,'EXTRA 09',*]"]

!!


如果您满意的话,能否给我的回答点赞/接受呢?实际上,我相信您可能没有足够的积分来点赞,但您可以通过点击“点赞按钮-积分数-反对按钮”左边的符号下方的按钮来接受我的回答。 - eyquem

1

该算法适用于挑剔的人,它不会很好地拆分你传递给它的每个字符串,只有像这样的字符串:

"Quantity [*,'EXTRA 05',*] [*,'EXTRA 09',*]"

"Quantity [*,'EXTRA 05',*]"

"Quantity [*,'EXTRA 05',*] [*,'EXTRA 10',*] [*,'EXTRA 07',*] [*,'EXTRA 09',*]"

string = "Quantity [*,'EXTRA 05',*] [*,'EXTRA 09',*]"
splitted_string = []

#This adds "Quantity" to the position 0 of splitted_string
splitted_string.append(string.split(" ")[0])     

#The for goes from 1 to the lenght of string.split(" "),increasing the x by 2
#The first iteration x is 1 and x+1 is 2, the second x=3 and x+1=4 etc...
#The first iteration concatenate "[*,'EXTRA" and "05',*]" in one string
#The second iteration concatenate "[*,'EXTRA" and "09',*]" in one string
#If the string would be bigger, it will works
for x in range(1,len(string.split(" ")),2):
    splitted_string.append("%s %s" % (string.split(" ")[x],string.split(" ")[x+1]))

当我执行代码时,分割后的字符串最终包含:
['Quantity', "[*,'EXTRA 05',*]", "[*,'EXTRA 09',*]"]
splitted_string[0] = 'Quantity'
splitted_string[1] = "[*,'EXTRA 05',*]"
splitted_string[2] = "[*,'EXTRA 09',*]"

我认为这正是您所寻找的。如果我错了,请告诉我,或者如果您需要对代码进行解释,请让我知道。希望能有所帮助。


使用string = "'zug hug'Quantity boondoggle 'fish face monkey dung' [*,'EXTRA 05',*] [*,'EXTRA 09',*]"进行尝试,你会发现在同一引号内有多个空格以及引号包含未引用的部分时会失败。 - Jack Aidley
我想字符串应该总是像“Quantity [,'EXTRA 05',]”或“Quantity [,'EXTRA 05',][,'EXTRA 07',]”。 - AlvaroAV
这个孩子真生气啊...如果我错了,我会接受的,对我来说没有问题,但是我再次阅读了问题,似乎他总是使用我之前提到的字符串进行操作。当然,如果你传递任何其他类型的字符串,我的代码就不起作用了...我本来以为不需要解释这一点,但我认为这是隐含的... - AlvaroAV
是的,如果你假设这些字符串都是完全相同的形式,那么你的解决方案就会起作用。虽然我认为,如果这些字符串都具有完全相同的形式,你可能可以更优雅地使用正则表达式来解决它。 - Jack Aidley

0

假设您想要一个通用的解决方案来在空格处拆分,但不在引号中的空格上:我不知道有没有Python库可以做到这一点,但这并不意味着没有。

在没有已知的预制解决方案的情况下,我会简单地自己编写。相对容易扫描字符串以查找空格,然后使用Python切片功能将字符串分成所需的部分。要忽略引号中的空格,只需包含一个标志,在遇到引号符号时打开和关闭空格感应。

这是我编写的一些代码来实现此目的,它没有经过广泛测试:

def spaceSplit(string) :
  last = 0
  splits = []
  inQuote = None
  for i, letter in enumerate(string) :
    if inQuote :
      if (letter == inQuote) :
        inQuote = None
    else :
      if (letter == '"' or letter == "'") :
        inQuote = letter

    if not inQuote and letter == ' ' :
      splits.append(string[last:i])
      last = i+1

  if last < len(string) :
    splits.append(string[last:])

  return splits

我认为分割函数比这更容易,并且不修改引号或双引号。 - AlvaroAV
这段代码不会修改引号或双引号吗?它也“有效”,不像你回答中的代码。 - Jack Aidley
只需将代码复制并粘贴到任何Python控制台中,它就能完美运行且易于理解。我并不是要侮辱你或你的代码,我也不知道为什么你回答得那么生气... 请尝试我的代码并告诉我哪里出了问题,因为我一遍又一遍地复制和粘贴,它都能完美运行。再次抱歉如果冒犯了你,我并不是有意这样做的。 - AlvaroAV
我既不感到被冒犯,也不感到生气。 - Jack Aidley

0

试试这个

def parseString(inputString):
    output = inputString.split()
    res = []
    count = 0
    temp = []
    for word in output:
        if (word.startswith('"')) and count % 2 == 0:
            temp.append(word)
            count += 1
        elif count % 2 == 1 and not word.endswith('"'):
            temp.append(word)
        elif word.endswith('"'):
            temp.append(word)
            count += 1
            tempWord = ' '.join(temp)
            res.append(tempWord)
            temp = []
        else:
            res.append(word)


    print(res)

输入:

parseString('This is "a test" to your split "string with quotes"')

输出: ['This', 'is', '"a test"', 'to', 'your', 'split', '"string with quotes"']


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接