2017-06-21 36 views
2

我已经喜欢字符串分割到字符和数字并存储在地图的Python

“A15B7C2”

它代表的字符数的字符串。

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

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

但是,如果我有一个像

字符串 'A15B7CD2Ef5'

它意味着的C count是1(其隐含的)和EF的计数是5(大写和小写的后续计为一个键)的结果,我得到

“CD” = 2(尚未correc T)
'EF'= 5(正确)

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

+0

所以,你不能再用一个或多个数字分割。你试图解决什么问题?你的字符串是字母数字吗? –

+0

@Wiktor:Did。.. [r] [^ \ W \ d _] + | \ d +“''r”(\ d + | \ s +)“''”([A-Za-z])([0 -9] *)“'和其他一些,但只是无法得到正确的正则表达式。 看着答案,结果是更多的焦点会有所帮助;)即使如此,我也不可能把整个事情写下来!行:) – holmes840

回答

6

你可以做到这一切一举:

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} 
+0

@Jan啊是的,谢谢你的更正。 –

+0

单线完整解决方案非常棒!非常感谢 :) – holmes840

0

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

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 
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')] 
0

与原来的逻辑是一致的。而不是使用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