【问题标题】:Split when character changes in PythonPython中字符更改时拆分
【发布时间】:2014-06-08 22:20:40
【问题描述】:

所以我有这个字符串。

6#666#665533999

我想将它解析成多个小字符串(或直到字符发生变化)并忽略#,这样我就可以像电话拨号盘一样替换6 = M or 666 = O or 9 = W

6#666#665533999 -> 6, 666, 66, 55, 33, 999

所以我使用split('#') 方法删除# 并且不知道下一步该做什么。我尝试了蛮力方法在一定程度上解决了它,但有没有更简单或更优雅的解决方案到这个?

【问题讨论】:

  • 那么6#666#665533999 会变成MONKEY 吗?
  • 另外,您想如何处理 Q 和 Z?不同的手机处理它们的方式不同
  • @inspectorG4dget 是的,感谢您添加。
  • @inspectorG4dget Q 将是 77Z 将是 9999

标签: python string parsing


【解决方案1】:

使用itertools.groupby:

>>> c = "6#666#665533999"
>>> ["".join(g) for k, g in groupby(c) if k != '#']
['6', '666', '66', '55', '33', '999']

然后有一个字典,将这些集合中的每一个映射到拨号盘中的一个字符。

cmap = {'77': 'Q', '9999': 'Z'} # And so forth..

【讨论】:

    【解决方案2】:

    这基本上是相同的逻辑,只是包装得更整齐一点:

    from itertools import groupby
    
    phone_chars = {
        "2": " ABC",
        "3": " DEF",
        "4": " GHI",
        "5": " JKL",
        "6": " MNO",
        "7": " PQRS",
        "8": " TUV",
        "9": " WXYZ",
        "#": ["", ""]
    }
    
    def decode(digit_str):
        return "".join(phone_chars[ch][len(list(it))] for ch,it in groupby(digit_str))
    

    然后

    >>> print(decode("6#666#665533999"))
    MONKEY
    

    编辑:

    Python 有很好的online documentation

    itertools.groupby 接受一个输入序列和一个可选的key 参数,它是一个评估函数——它接受一个值,对它做一些事情,然后返回结果。如果没有给出key函数,则默认为identity(即key = lambda x: x,取一个值,返回相同的值)。

    然后它将这个评估函数应用于输入序列中的每个项目,并返回一个(evaluated_value, iter(consecutive_items_having_the_same_evaluated_value))的序列。

    所以

    groupby("AABBBCCCDD")
    

    得到你

    iter((
        ("A", iter(("A", "A"))),
        ("B", iter(("B", "B", "B"))),
        ("C", iter(("C", "C", "C"))),
        ("D", iter(("D", "D")))
    ))
    

    或(演示自定义评估函数)

    groupby([1, 2, 3, 4, 5, 6, 7], key=lambda x: x//3)
    

    给予

    iter((
        (0, iter([1, 2])),      # 1//3 == 2//3 == 0
        (1, iter([3, 4, 5])),   # 3//3 == 4//3 == 5//3 == 1
        (2, iter([6, 7]))       # 6//3 == 7//3 == 2
    ))
    

    请注意,迭代器一次只能为您提供一个值,len 无法处理一个,因为无法知道迭代器可能返回多少个值。如果需要统计返回值,最简单的方法是len(list(iterable)) - 将所有返回值抓取到一个列表中,然后查看该列表有多少项。所以如果我们这样做

    [(ch, len(list(it))) for ch,it in groupby("6#666#665533999")]
    

    我们得到的是

    [
        ('6', 1),   # => 'M'
        ('#', 1),   # => ''
        ('6', 3),   # => 'O'
        ('#', 1),   # => ''
        ('6', 2),   # => 'N'
        ('5', 2),   # => 'K'
        ('3', 2),   # => 'E'
        ('9', 3)    # => 'Y'
    ]
    

    其中(按设计)恰好是phone_chars 所需的索引值。我们使用索引值来获取相应的字符——即phone_chars['6'][1] == 'M'——使用"".join()将它们连接在一起,并返回结果字符串("MONKEY")。

    【讨论】:

    • 我只是在搜索上述解决方案实际上在做什么,但仍然无法理解它。本周刚开始使用 python,并将其作为练习练习。我真的很想得到解释如果可以的话,请谈谈这里实际发生的事情。
    【解决方案3】:
    def encode(nums):
        return ["".join(g) for k, g in itertools.groupby(nums) if k != '#']
    
    
    chars = {str(n):dict(enumerate(chrs,1)) for n,chrs in enumerate("ABC DEF GHI JKL MNO PQRS TUV WXYZ".split(), 2)}
    
    nums = "6#666#665533999"
    nums = encode(nums)
    message = ''.join(chars[n[0]][len(n)] for n in nums)
    
    In [28]: message
    Out[28]: 'MONKEY'
    

    【讨论】:

      猜你喜欢
      • 2016-03-15
      • 1970-01-01
      • 1970-01-01
      • 2017-09-25
      • 1970-01-01
      • 1970-01-01
      • 2016-06-01
      • 2010-09-30
      • 1970-01-01
      相关资源
      最近更新 更多