我想知道是否有人可以帮助提出一个优雅的解决方案,如何将从路由器的格式为"4d12h33m59s"
的API中收集的时间字符串分割成碎片。
问题是字符串可能是动态大小。例如,它可以是"4d12h33m59s"
或"12h33m59s"
或"12y14w4d12h33m59s"
或"12m23s"
,"33s"
。
是否有任何优雅的方法来分割字符串并获得如下列表:
received_string = "12y14w4d12h33m59s"
time_list = convert_string(received_string)
print(time_list)
["12y","14w","4d","12h","33m","59s"]
答案 0 :(得分:7)
您可以使用regular expression:
import re
time_list = re.findall('\d+[a-z]', received_string)
re.findall()
function生成输入字符串中给定模式的所有匹配项的列表。这里的模式寻找一个或多个数字,后跟一个小写的ASCII字母。
你可以通过使用[ywdhms]
使得允许使用哪些字母变得更加挑剔,但如果你的输入结构合理,我就不用担心了。
演示:
>>> import re
>>> received_string = "12y14w4d12h33m59s"
>>> re.findall('\d+[a-z]', received_string)
['12y', '14w', '4d', '12h', '33m', '59s']
然而,您可能希望进一步拆分数字和字母,以便更容易将信息转换为更容易使用的格式,如datetime.timedelta()
对象,也许可以转换为字典:
{type_: int(count) for count, type_ in re.findall('(\d+)([a-z])', received_string)}
添加的(..)
分组会更改re.findall()
输出,以便为每个匹配生成一个元组,其中包含单独的组值(因此('12', 'y')
,('14', 'w')
等)。
这会产生
{'y': 12, 'w': 14, 'd': 4, 'h': 12, 'm': 33, 's': 59}
输入。
答案 1 :(得分:1)
import datetime, re, operator, functools
times = {'s': datetime.timedelta(seconds=1),
'm': datetime.timedelta(minutes=1),
'h': datetime.timedelta(hours=1),
'd': datetime.timedelta(days=1),
'w': datetime.timedelta(weeks=1),
'y': datetime.timedelta(days=365)}
fieldre = re.compile(r'(\d+)([{}])'.format(''.join(times.keys())))
samplevalue = "12y14w4d12h33m59s"
duration = functools.reduce(operator.add,
(times[unit]*int(value) for (value,unit) in
fieldre.findall(samplevalue)))
remains = fieldre.subn("", samplevalue)
if remains:
raise ValueError("Unexpected time fields in {!r}: {!r}".format(
samplevalue, remains))
不可否认,最后一点是一团糟。请注意,年份单位是粗略近似值(365天)。我使用dict.keys
提取这些单位并在正则表达式中允许它们,正则表达式中的括号生成值和单位作为一对,functools.reduce(operator.add, iterable)
代替sum
因为后者不适用于timedelta
。最后,我们有一个时间点,我们可以读取标准化的时间,例如: duration.total_seconds()
。
可能更有用的是,我添加了一种方法来检测我们是否使用subn
留下了一些东西。错误的数据可能比检测无效的转换更有害。