如何将字符串拆分为列表?

Posted

技术标签:

【中文标题】如何将字符串拆分为列表?【英文标题】:How do I split a string into a list? 【发布时间】:2010-09-10 10:58:54 【问题描述】:

如果我有这个字符串:

2+24*48/32

创建此列表的最有效方法是什么:

['2', '+', '24', '*', '48', '/', '32']

【问题讨论】:

您想将一个字符串拆分为一个列表,但又不想使用 .split() 因为它返回一个列表?你在自相矛盾。如果您不想要列表,那么您想要想要什么? @Jim:我认为 Jibmo 的意思是 split() 只允许你指定一个分隔符,所以他必须为 '+' 调用一次,为 '-' 调用一次,为 '/ 调用一次'等... 抱歉解释不好,我的意思是 split 将返回一个列表,这意味着对于第二次拆分,我现在需要遍历列表中的字符串。语法不正确的例子.. string = "2+2-2" list = string.split(+) 返回 ['2', '+', '2-2'] 现在我需要遍历 3 个字符串 您应该提到您正在开发一个程序,该程序需要能够将这些字符串作为算术表达式进行计算。 Jerub 的回答涵盖了这一点,但那是因为他是一个读心术。 为什么不直接使用SymPy?它应该做你想要达到的目标。 【参考方案1】:

恰好你想要拆分的标记已经是 Python 标记,所以你可以使用内置的 tokenize 模块。它几乎是一条线;这个程序:

from io import StringIO
from tokenize import generate_tokens

STRING = 1
print(
    list(
        token[STRING]
    for token in generate_tokens(StringIO("2+24*48/32").readline)
    if token[STRING]
    )
)

产生这个输出:

['2', '+', '24', '*', '48', '/', '32']

【讨论】:

很好的答案,我没有意识到这个模块存在:) 代替或手动分配STRING=1,您可以通过执行from token import STRING 来使用token 模块中的常量。如果您需要多个令牌常量,这将特别有用。 为什么这么复杂的答案会被评为这么高?这是一个非常简单的问题。找到最简洁、最简洁的答案时发生了什么?【参考方案2】:

您可以使用re 模块中的split

re.split(pattern, string, maxsplit=0, flags=0)

通过出现的模式分割字符串。如果捕获括号 在pattern中使用,那么pattern中所有组的文本都是 也作为结果列表的一部分返回。

示例代码:

import re
data = re.split(r'(\D)', '2+24*48/32')

\D

当未指定 UNICODE 标志时,\D 匹配任何非数字 特点;这等价于集合 [^0-9]。

【讨论】:

【参考方案3】:
>>> import re
>>> re.findall(r'\d+|\D+', '2+24*48/32=10')

['2', '+', '24', '*', '48', '/', '32', '=', '10']

匹配连续数字或连续非数字。

每个匹配项都作为列表中的一个新元素返回。

根据使用情况,您可能需要更改正则表达式。比如如果你需要匹配带小数点的数字。

>>> re.findall(r'[0-9\.]+|[^0-9\.]+', '2+24*48/32=10.1')

['2', '+', '24', '*', '48', '/', '32', '=', '10.1']

【讨论】:

【参考方案4】:

这看起来像是一个解析问题,因此我不得不提出一个基于解析技术的解决方案。

虽然您似乎想要“拆分”这个字符串,但我认为您真正想要做的是“标记化”它。标记化或词法分析是解析之前的编译步骤。我在编辑中修改了我的原始示例,以在此处实现适当的递归体面解析器。这是手动实现解析器的最简单方法。

import re

patterns = [
    ('number', re.compile('\d+')),
    ('*', re.compile(r'\*')),
    ('/', re.compile(r'\/')),
    ('+', re.compile(r'\+')),
    ('-', re.compile(r'\-')),
]
whitespace = re.compile('\W+')

def tokenize(string):
    while string:

        # strip off whitespace
        m = whitespace.match(string)
        if m:
            string = string[m.end():]

        for tokentype, pattern in patterns:
            m = pattern.match(string)
            if m:
                yield tokentype, m.group(0)
                string = string[m.end():]

def parseNumber(tokens):
    tokentype, literal = tokens.pop(0)
    assert tokentype == 'number'
    return int(literal)

def parseMultiplication(tokens):
    product = parseNumber(tokens)
    while tokens and tokens[0][0] in ('*', '/'):
        tokentype, literal = tokens.pop(0)
        if tokentype == '*':
            product *= parseNumber(tokens)
        elif tokentype == '/':
            product /= parseNumber(tokens)
        else:
            raise ValueError("Parse Error, unexpected %s %s" % (tokentype, literal))

    return product

def parseAddition(tokens):
    total = parseMultiplication(tokens)
    while tokens and tokens[0][0] in ('+', '-'):
        tokentype, literal = tokens.pop(0)
        if tokentype == '+':
            total += parseMultiplication(tokens)
        elif tokentype == '-':
            total -= parseMultiplication(tokens)
        else:
            raise ValueError("Parse Error, unexpected %s %s" % (tokentype, literal))

    return total

def parse(tokens):
    tokenlist = list(tokens)
    returnvalue = parseAddition(tokenlist)
    if tokenlist:
        print 'Unconsumed data', tokenlist
    return returnvalue

def main():
    string = '2+24*48/32'
    for tokentype, literal in tokenize(string):
        print tokentype, literal

    print parse(tokenize(string))

if __name__ == '__main__':
    main()

括号处理的实现留给读者作为练习。这个例子会在加法之前正确地进行乘法运算。

【讨论】:

我现在正在阅读标记化以了解它。所以我不能说问题出在哪里,尽管我认为这个脚本将同时评估 * 和 / ,这是不正确的。 8/2*2 这个字符串应该打印 2 的结果,但它打印的结果是 8。 对不起,我错了,总是把 bomdas 从字面上看,结果乘法和除法在优先顺序上是相等的,先出现的先计算 tokenize:为什么要使用re 删除内置字符串函数上的空格?【参考方案5】:

这是一个解析问题,因此 regex 和 split() 都不是“好的”解决方案。请改用解析器生成器。

我会仔细查看pyparsing。 Python Magazine 也有一些关于 pyparsing 的不错的文章。

【讨论】:

【参考方案6】:

s = "2+24*48/32"

p = re.compile(r'(\W+)')

p.split(s)

【讨论】:

【参考方案7】:

正则表达式:

>>> import re
>>> splitter = re.compile(r'([+*/])')
>>> splitter.split("2+24*48/32")

您可以扩展正则表达式以包含您想要拆分的任何其他字符。

【讨论】:

【参考方案8】:

另一个解决方案是完全避免编写这样的计算器。编写 RPN 解析器要简单得多,并且没有使用中缀表示法编写数学所固有的任何歧义。

import operator, math
calc_operands = 
    '+': (2, operator.add),
    '-': (2, operator.sub),
    '*': (2, operator.mul),
    '/': (2, operator.truediv),
    '//': (2, operator.div),
    '%': (2, operator.mod),
    '^': (2, operator.pow),
    '**': (2, math.pow),
    'abs': (1, operator.abs),
    'ceil': (1, math.ceil),
    'floor': (1, math.floor),
    'round': (2, round),
    'trunc': (1, int),
    'log': (2, math.log),
    'ln': (1, math.log),
    'pi': (0, lambda: math.pi),
    'e': (0, lambda: math.e),


def calculate(inp):
    stack = []
    for tok in inp.split():
        if tok in self.calc_operands:
            n_pops, func = self.calc_operands[tok]
            args = [stack.pop() for x in xrange(n_pops)]
            args.reverse()
            stack.append(func(*args))
        elif '.' in tok:
            stack.append(float(tok))
        else:
            stack.append(int(tok))
    if not stack:
        raise ValueError('no items on the stack.')
    return stack.pop()
    if stack:
        raise ValueError('%d item(s) left on the stack.' % len(stack))

calculate('24 38 * 32 / 2 +')

【讨论】:

你为什么不直接去实现,它只会多 5 行!【参考方案9】:
>>> import re
>>> my_string = "2+24*48/32"
>>> my_list = re.findall(r"-?\d+|\S", my_string)
>>> print my_list

['2', '+', '24', '*', '48', '/', '32']

这样就可以了。我以前也遇到过这种问题。

【讨论】:

【参考方案10】:

这并不能完全回答问题,但我相信它可以解决您想要实现的目标。我会将其添加为评论,但我还没有这样做的权限。

我个人会直接通过 exec 来利用 Python 的数学功能:

表达式 = "2+24*48/32"exec "result = " + 表达式打印 结果 38

【讨论】:

如果我错了,请原谅我,但使用result = eval(expression)不是更好吗? 确实会;我很抱歉。【参考方案11】:

我确定蒂姆的意思是

splitter = re.compile(r'([\D])'). 

如果你完全复制他的内容,你只会得到digits 而不是operators

【讨论】:

以上是关于如何将字符串拆分为列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过特定的字符串元素将字符串列表拆分为字符串的子列表

如何将逗号分隔的字符串拆分为字符串列表?

您知道如何将字符串列表拆分为不同的变量吗?

如何将字符串拆分为列表并在python中将两个已知令牌合并为一个?

python映射字符串拆分列表

REGEX 使用关键字将字符串拆分为列表