将字符串拆分为不同的数据类型

4

我想把下面的字符串转换为:

s = '1|2|a|b'

to

[1, 2, 'a', 'b']

是否可以在一行内完成转换?


更复杂的数据类型呢?你期望有多少种数据类型?你尝试过什么吗?你的代码有任何特定的问题吗?为什么要在一行中完成这个任务? - vaultah
@vaultah 首先只考虑了 intstring 但我正在思考如何将该解决方案用于 float - wannik
5个回答

13

是否可以用一行代码进行转换?

是的,这是可能的。但是怎么做呢?

方法的算法

  • 使用 str.split 将字符串拆分为其组成部分。其输出为:

    >>> s = '1|2|a|b'
    >>> s.split('|')
    ['1', '2', 'a', 'b']
    
  • 现在我们已经解决了一半的问题。接下来我们需要遍历拆分后的字符串,并检查每个元素是字符串还是整数。为此,我们使用

  • 可以轻松地将列表推导式写成 [i for i in s.split('|')]。但是如何在其中添加一个if子句呢?这在一行列表推导式:if-else变体中有介绍。现在我们知道哪些元素是int,哪些不是,我们就可以轻松地对其调用内置的int函数了。

    因此最终代码将如下所示

  •   [int(i) if i.isdigit() else i for i in s.split('|')]
    

现在进行一个小演示:

>>> s = '1|2|a|b'
>>> [int(i) if i.isdigit() else i for i in s.split('|')]
[1, 2, 'a', 'b']

正如我们所看到的,输出结果与预期相符。


请注意,如果要转换的类型很多,则此方法不适用。


7

对于负数或一个语句里包含多种类型的数据,你不能使用同一行来完成它。但是你可以使用一个函数,该函数可以适用于多种类型,其中使用了ast.literal_eval

from ast import  literal_eval
def f(s, delim):
    for ele in s.split(delim):
        try:
            yield literal_eval(ele)
        except ValueError:
            yield ele

s = '1|-2|a|b|3.4'

print(list(f(s,"|")))
[1, -2, 'a', 'b', 3.4]

感谢您建议使用 ast.literal_eval。它非常有用。现在我可以使用两行代码将数据转换为多种类型:from ast import literal_eval[literal_eval(e) if e[-1].isdigit() else e for e in s.split('|')] - wannik
@wannik 不用担心,如果你想要一行代码,可以尝试使用list(map(literal_eval, re.sub('(?!\|)([A-Za-z]+)', "'" + r"\1" + "'", s).split("|"))),将字符用引号括起来。但是函数方法更加健壮可靠。 - Padraic Cunningham

2
另一种方法是使用内置的map方法:
>>> s='1|2|a|b'
>>> l = map(lambda x: int(x) if x.isdigit() else x, s.split('|'))
>>> l
[1, 2, 'a', 'b']

如果是Python3,则:
>>> s='1|2|a|b'
>>> l = list(map(lambda x: int(x) if x.isdigit() else x, s.split('|')))
>>> l
[1, 2, 'a', 'b']

由于Python3中的map会返回一个生成器,因此您必须将其转换为list


你在这里真的不需要使用map-lambda。 - Eugene Soldatov

1
如果允许使用辅助函数,即使进行任意多个或复杂的转换,也可以在“一行代码”中完成。Python原生不具备“将此字符串转换为应该表示的类型”的功能,因为它“应该”表示的内容是模糊的,可能会随应用程序而变化。
def convert(input):
    converters = [int, float, json.loads]
    for converter in converters:
        try:
            return converter(input)
        except (TypeError, ValueError):
            pass
    # here we assume if all converters failed, it's just a string
    return input

s = "1|2.3|a|[4,5]"
result = [convert(x) for x in s.split("|")]

这一点与Python的风格格格不入。 - Netwave
也许你可以提出改进的建议?我不确定哪一部分让你感到如此严重。 - GrandOpener
不是有意冒犯,但在我看来,一堆try except语句并不是一个好的编程实践。 - Netwave
我建议不要硬编码类型,这是一个低级的解决方案。也许有一个注册类型列表来进行转换会更好。 - Netwave
好的建议。我已经改进了答案以适应。 - GrandOpener

1
如果你有各种数据类型(不仅仅是字符串和整数),我相信这可以完成工作。
s = '1|2|a|b|[1, 2, 3]|(1, 2, 3)'
print [eval(x) if not x.isalpha() else x for x in s.split("|")]

# [1, 2, 'a', 'b', [1, 2, 3], (1, 2, 3)]

如果存在诸如“b1”之类的元素,则此操作将失败。


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