【问题标题】:Split string into character and numbers and store in a map Python将字符串拆分为字符和数字并存储在地图 Python 中
【发布时间】:2017-06-21 18:03:47
【问题描述】:

我有一个类似

的字符串

'A15B7C2'

表示字符的个数。

我现在正在使用 re 将其拆分为字符和数字。之后最终将其存储在字典中

import re
data_str = 'A15B7C2'
re.split("(\d+)", data_str)
# prints --> ['A', '15', 'B', '7', 'C', '2', '']

但是如果我有一个像

这样的字符串

'A15B7CD2Ef5'

这意味着 C 的计数是 1(它的隐式),而 Ef 的计数是 5。(大写和随后的小写作为一个键)因此我得到 ​​p>

'CD' = 2(不正确)
'Ef' = 5(正确)

如何修改它以提供正确的计数? 解析和获取计数并存储在字典中的最佳方法是什么?

【问题讨论】:

  • 因此,您不能再使用一位或多位数字进行拆分。你尝试过什么来解决这个问题?你的字符串是字母数字的吗?
  • @Wiktor : 尝试过.. r"[^\W\d_]+|\d+" r"(\d+|\s+)" "([A-Za-z])([0-9]*)" 和其他一些人,但只是无法正确使用正则表达式。看着答案,结果发现多一点注意力会有所帮助;)即使那样,我也无法将整件事写下来!行:)

标签: python regex string split numbers


【解决方案1】:

你可以一举搞定:

In [2]: s = 'A15B7CD2Ef5'

In [3]: {k: int(v) if v else 1 for k,v in re.findall(r"([A-Z][a-z]?)(\d+)?", s)}
Out[3]: {'A': 15, 'B': 7, 'C': 1, 'D': 2, 'Ef': 5}

正则表达式本质上是您的需求的直接翻译,利用.findall 和捕获组:

r"([A-Z][a-z]?)(\d+)?"

本质上,一个大写字母后跟一个小写字母作为第一组,一个数字可能存在也可能不存在作为第二组(如果不存在则返回''

一个更棘手的例子:

In [7]: s = 'A15B7CD2EfFGHK5'

In [8]: {k: int(v) if v else 1 for k,v in re.findall(r"([A-Z][a-z]?)(\d+)?", s)}
Out[8]: {'A': 15, 'B': 7, 'C': 1, 'D': 2, 'Ef': 1, 'F': 1, 'G': 1, 'H': 1, 'K': 5}

最后,用一个更棘手的例子来分解它:

In [10]: s = 'A15B7CD2EfFGgHHhK5'

In [11]: re.findall(r"([A-Z](?:[a-z])?)(\d+)?", s)
Out[11]:
[('A', '15'),
 ('B', '7'),
 ('C', ''),
 ('D', '2'),
 ('Ef', ''),
 ('F', ''),
 ('Gg', ''),
 ('H', ''),
 ('Hh', ''),
 ('K', '5')]

In [12]: {k: int(v) if v else 1 for k,v in re.findall(r"([A-Z][a-z]?)(\d+)?", s)}
Out[12]:
{'A': 15,
 'B': 7,
 'C': 1,
 'D': 2,
 'Ef': 1,
 'F': 1,
 'Gg': 1,
 'H': 1,
 'Hh': 1,
 'K': 5}

【讨论】:

  • 一条线完整的解决方案很棒!非常感谢:)
【解决方案2】:

您可以使用一些正则表达式逻辑和.span():

([A-Z])[a-z]*(\d+)

a demo on regex101.com


Python 中,这将是:
import re

string = "A15B7CD2Ef5"
rx = re.compile(r'([A-Z])[a-z]*(\d+)')

def analyze(string=None):
    result = []; lastpos = 0;
    for m in rx.finditer(string):
        span = m.span()
        if lastpos != span[0]:
            result.append((string[lastpos], 1))
        else:
            result.append((m.group(1), m.group(2)))
        lastpos = span[1]
    return result

print(analyze(string))
# [('A', '15'), ('B', '7'), ('C', 1), ('E', '5')]

【讨论】:

    【解决方案3】:

    搜索字符串中的字母,而不是数字。

    import re
    data_str = 'A15B7C2'
    temp = re.split("([A-Za-z])", data_str)[1:]    # First element is just "", don want that
    temp= [a if a != "" else "1" for a in temp]    # add the 1's that were implicit in the original string
    finalDict = dict(zip(temp[0::2], temp[1::2]))  # turn the list into a dict
    

    【讨论】:

      【解决方案4】:

      与您的原始逻辑保持一致。我们可以找到所有数字,而不是使用 re.split(),在第一个匹配时拆分字符串,为下一次拆分保留字符串的后半部分,并将您的对存储为元组以供以后使用。

      import re
      
      raw = "A15B7CD2Ef5"
      # find all the numbers
      found = re.findall("(\d+)", raw)
      # save the pairs as a list of tuples
      pairs = []
      # check that numbers where found
      if found:
          # iterate over all matches
          for f in found:
              # split the raw, with a max split of one, so that duplicate numbers don't cause more then 2 parts
              part = raw.split(f, 1)
              # set the original string to the second half of the split
              raw = part[1]
              # append pair
              pairs.append((part[0], f))
      
      
      
      # Now for fun expand values
      long_str = ""
      for p in pairs:
          long_str += p[0] * int(p[1])
      
      print pairs
      print long_str
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-02
        • 2017-03-07
        • 1970-01-01
        • 2014-12-17
        • 1970-01-01
        相关资源
        最近更新 更多