【问题标题】:Split string to various data types将字符串拆分为各种数据类型
【发布时间】:2016-04-03 13:53:37
【问题描述】:

我想转换以下字符串:

s = '1|2|a|b'

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

是否可以在一行中进行转换?

【问题讨论】:

  • 更复杂的数据类型呢?您期望有多少种数据类型?你试过什么吗?您的代码有任何具体问题吗?你为什么要在一行中做到这一点?
  • @vaultah 一开始只有intstring,但我也在考虑如何使用float 的解决方案。

标签: python string list


【解决方案1】:

是否可以在一行中进行转换?

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

该方法的算法

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

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

  • 列表推导式可以很容易地写成[i for i in s.split('|')]。但是我们如何在那里添加一个if 子句呢?这在One-line list comprehension: if-else variants 中有介绍。现在我们知道哪些元素是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']

正如我们所见,输出与预期一致。


请注意,如果要转换的类型很多,这种方法不适合。

【讨论】:

    【解决方案2】:

    您不能在一行中处理负数或大量混合类型,但您可以使用适用于多种类型的函数 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 不用担心,如果你想要单行,你可以试试list(map(literal_eval, re.sub('(?!\|)([A-Za-z]+)', "'" + r"\1" + "'", s).split("|")))),将字符用引号括起来,但函数方法更健壮
    【解决方案3】:

    如果允许使用辅助函数,则可以“在一行中”进行任意多次或复杂的转换。 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("|")]
    

    【讨论】:

    • 这只是pythonic
    • 也许你可以提出改进它的方法,然后呢?我不确定它的哪一部分对你来说如此令人震惊。
    • 不想冒犯,但在我看来,一堆尝试例外根本不是一个好习惯。
    • 并建议我说对类型进行编码是一个糟糕的解决方案,也许有一个要转换的注册类型列表会更好。
    • 好建议。我已经改进了适合的答案。
    【解决方案4】:

    另一种方式,是使用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。
    【解决方案5】:

    如果你有各种数据类型(超过 str 和 int),我相信这可以完成工作。

    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”等元素则失败

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-02
      • 2016-10-31
      相关资源
      最近更新 更多