从字符串中解析格式奇怪的时间表达式

Parsing a weirdly formatted time expression from a string

我正在尝试解析格式化字符串。我需要知道我检索到的每个项目已经完成了多少小时、分钟和秒。

我收到的数据是这种格式,例如:

PT5H12M3S,表示5小时12分3秒。

但是,如果工作时间少于一个小时,则不会显示:

PT12M3S,表示12分3秒

更重要的是,如果没有在项目上工作(或仅不到一分钟),数据将显示为:

PT0S

如果一个项目只有完整的工作时间,它将显示为:

PT5H

我尝试使用以下代码解析数据:

estimated = track_data['project']['estimate']['estimate'].split('PT')[1]
estimated_hours = estimated.split('H')[0]
estimated_minutes = estimated_hours.split('M')[0]
estimated_seconds = estimated_minutes.split('S')[0]

但此解决方案仅适用于数据格式为 PT5H12M3S 的情况。所有其他格式,这是错误的。例如,如果我得到数据 PT5H,那么估计的小时数将为 5,而且估计的分钟数和秒数也将为 5。显然这不是我们想要的。

有没有人可以指导我在哪里看?我用 split 尝试了一些其他的东西,但它似乎不起作用,因为如果它找不到 'M' 或 'S',它只会继续重复相同的数字。

希望这是有道理的,并提前致谢。

您可以使用正则表达式和正则表达式中的组来捕获小时、分钟和秒 - 所有这些都可以是可选的。

大致如下: /PT(\d*)H?(\d*)M?(\d*)S?/

括号捕获组。因此您的捕获组将包含小时、分钟和秒(所有这些都是可选的)。

但是正则表达式的可读性不高。我强烈建议尝试像 Parsec 这样的解析器组合器库。解析器组合器更具可读性和可维护性,编写起来很愉快。

您可以为此使用正则表达式:

import re

PROJECT_TIME_REGEX = re.compile(r'PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?')

def get_project_time(s):
    m = PROJECT_TIME_REGEX.match(s)
    if not m:
        raise ValueError('invalid string')
    hour, min, sec = (int(g) if g is not None else 0 for g in m.groups())
    return hour, min, sec

print(get_project_time('PT5H12M3S'))
# (5, 12, 3)
print(get_project_time('PT12M3S'))
# (0, 12, 3)
print(get_project_time('PT0S'))
# (0, 0, 0)
print(get_project_time('PT5H'))
# (5, 0, 0)

这个怎么样?

import re

def parsept(ptstring):
    regex = re.compile(
            r'PT'
            r'(?:(?P<h>\d+)H)?'
            r'(?:(?P<m>\d+)M)?'
            r'(?:(?P<s>\d+)S)?')
    m = regex.match(ptstring)
    if m:
        return (int(m.group('h')) if m.group('h') else 0, 
            int(m.group('m') if m.group('m') else 0,
            int(m.group('s') if m.group('s') else 0)
    # else
    raise ValueError('{0} does not look like a valid PTxHyMzS string'.format(ptstring))

没有正则表达式的解决方案,基于条件

def parse_time(str_to_parse):
    str_to_parse = str_to_parse.split('PT')[1]
    time_units = ['H', 'M', 'S'] #this needs to always be in left to right or bigger to smaller order
    estimated_time = {k: 0 for k in time_units} 
    for k in time_units:
        if k in str_to_parse:
            left, right = str_to_parse.split(k)
            estimated_time[k], str_to_parse = int(left), right
    return estimated_time

estimated = "PT12M3S"
final_time = parse_time(estimated)
print(final_time)
{'H': 0, 'M': 12, 'S': 3}

我希望这段代码有意义。这是一种非常简单的方法,您可以循环遍历字符串的字符,将数字添加到当前并在到达字母字符后对其进行评估('S'、'M'、'H') .

estimated = 'PT5H'
clean = estimated.split('PT')[1]
seconds = 0
minutes = 0
hours = 0
current = ''

for char in clean:
    if char.isdigit():
        current += char
    else:
        if char == 'S':
            seconds = int(current)
        elif char == 'M':
            minutes = int(current)
        else:
            hours = int(current)

        current = ''

print(hours, minutes, seconds)