如何将描述时间的字符串转换为秒?

Posted

技术标签:

【中文标题】如何将描述时间的字符串转换为秒?【英文标题】:How to convert a string describing time into seconds? 【发布时间】:2020-12-24 12:09:13 【问题描述】:

我正在尝试制作一个函数将时间字符串(来自用户)转换为秒。

我想做的是让用户将时间输入为字符串,例如:

"one hour and forty five minutes" 

然后将其分解为几秒钟。所以上面的输出将是

6300 seconds

【问题讨论】:

你尝试了什么? 如果您是“从头开始”,您可能需要编写一个解析器,首先您需要定义一个语法来描述输入可能是什么。顺便说一句,在英语中这个数字是“四十五”。 你可能会发现this关于将单词转换为数字的帖子很有帮助。 检查这个:link 或使用word2number 我找到了一个很好的方法来做到这一点(或者至少我是这么认为的):我只需要使用通常的 UserInput 字符串并稍微清理一下:一小时四十五分钟变成四十五岁;然后我会知道从左到右我会有 H:M:S,用 word2number 将它们转换为整数,然后做这样的事情link 【参考方案1】:

如果您想从头开始,那么其他答案都很好。以下是您无需输入太多内容即可完成的操作:

您需要为此解决方案安装 word2number

from word2number import w2n
import re
def strTimeToSec(s):
    s = s.replace(' and', '')
    time = re.split(' hour| hours| minute| minutes| second| seconds', s)[:-1]
    if not('hour' in s):
        time = ['zero']+time
    elif not('minute' in s):
        time = [time[0]]+['zero']+[time[1]]
    elif not('second' in s):
        time = time+['zero']
    time = [w2n.word_to_num(x) for x in time]
    out = time[0]*3600+time[1]*60+time[2]
    return str(out)+' seconds'

>>> print(strTimeToSec('one hour and forty five minute'))

6300 seconds

>>> print(strTimeToSec('one hour forty five minute and thirty three seconds'))

6333 seconds

【讨论】:

【参考方案2】:

这不是一件容易的事,没有一种确定的方法可以做到这一点,或者我不知道。但我分享了一段代码,可以给你一个想法。 首先,您需要读取输入字符串并且需要拆分它。拆分数据时,您应该搜索“小时”或“分钟”等关键字符串。在此之后,您需要获取此值并在您已经定义数字的字符串版本的数据集中进行搜索。然后,你需要定义一些规则,例如(四十,五十它们都以ty结尾,你可以在字符串中搜索这些东西。)

但是,用户可以输入无限可能,因此您应该定义限制。我刚刚分享了我对如何解决此类问题的看法,但我可能会遗漏一些要点。

def convertSeconds(n_hours,n_minutes):
        return n_hours * 3600 + n_minutes *60
    
    dataSet = 
        "one": 1,
        "two": 2,
        "three": 3,
        "four": 4,
        "five": 5,
        "six": 6,
        "seven":7,
        "eight":8,
        "nine":9,
        "hundred":100,
        "hundreds":100,
        "thousand" : 1000,
        "millions" : 1000000
        #etc...
    
    
    time = input('Please Enter Date As String : ')
    word_array = time.split()
    idx = 0
    idx_hour = 0
    for word in word_array:
        if word == "hour":
            n_hours = word_array[0:idx]
            idx_hour = idx
        if word == "hours":
            n_hours = word_array[0:idx]
            idx_hour = idx
        if word == "and":
            idx_hour = idx_hour +1
        if word == "minute":
            n_minutes = word_array[idx_hour+1:idx]
        if word == "minutes":
            n_minutes = word_array[idx_hour+1:idx]
        idx = idx + 1
    total_hours = 0
    total_minutes = 0
    for counter in range(len(n_hours)):
        value = dataSet[n_hours[counter]]
        if n_hours[counter] == "hundreds" or n_hours[counter] == "hundred":
                 value = dataSet[n_hours[counter-1]] * 100
                 total_hours = total_hours - dataSet[n_hours[counter-1]]
        total_hours = total_hours + value
    
    
    for counter in range(len(n_minutes)):
        value = dataSet[n_minutes[counter]]
        total_minutes = total_minutes + value
    
    print("Your Time in Seconds : ",convertSeconds(total_hours,total_minutes))

Please Enter Date As String : two hundred hours and five minutes
Your Time in Seconds :  720300

【讨论】:

【参考方案3】:

你可以用一个很长的数字字典来做到这一点:

def parse_int(string):
    numbers = 'zero': 0,
               'one': 1,
               'two': 2,
               'three': 3,
               'four': 4,
               'five': 5,
               'six': 6,
               'seven': 7,
               'eight': 8,
               'nine': 9,
               'ten': 10,
               'eleven': 11,
               'twelve': 12,
               'thirteen': 13,
               'fourteen': 14,
               'fifteen': 15,
               'sixteen': 16,
               'seventeen': 17,
               'eighteen': 18,
               'nineteen': 19,
               'twenty': 20,
               'twenty-one': 21,
               'twenty-two': 22,
               'twenty-three': 23,
               'twenty-four': 24,
               'twenty-five': 25,
               'twenty-six': 26,
               'twenty-seven': 27,
               'twenty-eight': 28,
               'twenty-nine': 29,
               'thirty': 30,
               'thirty-one': 31,
               'thirty-two': 32,
               'thirty-three': 33,
               'thirty-four': 34,
               'thirty-five': 35,
               'thirty-six': 36,
               'thirty-seven': 37,
               'thirty-eight': 38,
               'thirty-nine': 39,
               'forty': 40,
               'forty-one': 41,
               'forty-two': 42,
               'forty-three': 43,
               'forty-four': 44,
               'forty-five': 45,
               'forty-six': 46,
               'forty-seven': 47,
               'forty-eight': 48,
               'forty-nine': 49,
               'fifty': 50,
               'fifty-one': 51,
               'fifty-two': 52,
               'fifty-three': 53,
               'fifty-four': 54,
               'fifty-five': 55,
               'fifty-six': 56,
               'fifty-seven': 57,
               'fifty-eight': 58,
               'fifty-nine': 59,
               'sixty': 60,
               'sixty-one': 61,
               'sixty-two': 62,
               'sixty-three': 63,
               'sixty-four': 64,
               'sixty-five': 65,
               'sixty-six': 66,
               'sixty-seven': 67,
               'sixty-eight': 68,
               'sixty-nine': 69,
               'seventy': 70,
               'seventy-one': 71,
               'seventy-two': 72,
               'seventy-three': 73,
               'seventy-four': 74,
               'seventy-five': 75,
               'seventy-six': 76,
               'seventy-seven': 77,
               'seventy-eight': 78,
               'seventy-nine': 79,
               'eighty': 80,
               'eighty-one': 81,
               'eighty-two': 82,
               'eighty-three': 83,
               'eighty-four': 84,
               'eighty-five': 85,
               'eighty-six': 86,
               'eighty-seven': 87,
               'eighty-eight': 88,
               'eighty-nine': 89,
               'ninety': 90,
               'ninety-one': 91,
               'ninety-two': 92,
               'ninety-three': 93,
               'ninety-four': 94,
               'ninety-five': 95,
               'ninety-six': 96,
               'ninety-seven': 97,
               'ninety-eight': 98,
               'ninety-nine': 99
    powers = 'hundred': 10 ** 2,
              'thousand': 10 ** 3,
              'million': 10 ** 6,
              'billion': 10 ** 9,
              'quadrillion': 10 ** 15,
              'quintillion': 10 ** 18,
              'sextillion': 10 ** 21,
              'septillion': 10 ** 24,
              'octillion': 10 ** 27,
              'nonillion': 10 ** 30,
              'decillion': 10 ** 33,
              'undecillion': 10 ** 36,
              'duodecillion': 10 ** 39,
              'tredecillion': 10 ** 42,
              'quattuordecillion': 10 ** 45,
              'quindecillion': 10 ** 48,
              'sexdecillion': 10 ** 51,
              'septemdecillion': 10 ** 54,
              'octodecillion': 10 ** 57,
              'novemdecillion': 10 ** 60,
              'vigintillion': 10 ** 63,
              'vigintunillion': 10 ** 66,
              'unvigintillion': 10 ** 66,
              'duovigintillion': 10 ** 69,
              'vigintiduoillion': 10 ** 69,
              'vigintitrillion': 10 ** 72,
              'trevigintillion': 10 ** 72,
              'vigintiquadrillion': 10 ** 75,
              'quattuorvigintillion': 10 ** 75,
              'quinvigintillion': 10 ** 78,
              'vigintiquintrillion': 10 ** 78,
              'vigintisextillion': 10 ** 81,
              'sexvigintillion': 10 ** 81,
              'vigintiseptillion': 10 ** 84,
              'septvigintillion': 10 ** 84,
              'octovigintillion': 10 ** 87,
              'vigintoctillion': 10 ** 87,
              'vigintinonillion': 10 ** 90,
              'nonvigintillion': 10 ** 90,
              'trigintillion': 10 ** 93,
              'untrigintillion': 10 ** 96,
              'duotrigintillion': 10 ** 99,
              'googol': 10 ** 100,
              'centillion': 10 ** 303
    
    result = 0
    a = string.split(" ")
    b = []
    
    for c in a:
        if c in numbers:
            b.append(c)
        elif c in powers:
            b[-1] += " " + c
        elif c == "and":
            continue
        else:
            print("INVALID WORD:",c)
            return

    for d, e in enumerate(b):
        if len(e.split(" ")) == 1:
            b[d] = numbers[e]
        else:
            b[d] = e.split(" ")
            b[d][0] = numbers[b[d][0]]
            f = 1
            while f < len(b[d]):
                b[d][f] = powers[b[d][f]]
                f += 1
    
    if not(isinstance(b[0], int)):
       while len(b[0]) > 2:
           b[0][1] *= b[0][2]
           b[0].pop(2)
    
    while len(b):
        if len(b) == 1:
            if isinstance(b[0], int):
                result += b[0]
                b.pop(0)
            else:
                while len(b[0]) > 1:
                    b[0][0] *= b[0][1]
                    b[0].pop(1)
                result += b[0][0]
                b.pop(0)
        else:
            if isinstance(b[1], int):
                b[1] += b[0][0] * b[0][1]
                b.pop(0)
            else:
                while len(b[1]) > 2:
                    b[1][1] *= b[1][2]
                    b[1].pop(2)
                
                if b[0][1] < b[1][1]:
                    b[1][0] += b[0][0] * b[0][1]
                    b.pop(0)
                else:
                    result += b[0][0] * b[0][1]
                    b.pop(0)
    
    return result

hours, minutes = input(">>> ").split(" and ")
seconds = parse_int(hours.rsplit(' ', 1)[0]) * 3600 + \
          parse_int(minutes.rsplit(' ', 1)[0]) * 60
print(seconds)

试运行:

>>> one billion hours and twelve minutes

输出:

3600000000720

致谢:https://codereview.stackexchange.com/a/253014/229550

【讨论】:

【参考方案4】:

parsedatetime 库可以完成部分工作。

from parsedatetime import Calendar, Constants

c = Calendar(Constants(usePyICU=False))
c.parse("1 minute and 3 hours")

将返回一个时间结构,遗憾的是包含整个日期。如果您输入的时间超过 24 小时,则会尝试重新计算日期。 而且,数字必须以数字而不是单词的形式呈现,但您可以使用 replace() 提前格式化您的字符串。

一旦你有了时间结构,你可以使用time.mktime()将它转换为Unix以来的秒数,然后你可以减去当前时间的秒数,或者更安全,在parse()方法中输入开始日期并减去它.

这是不完美的,但我使用dateutil.parser.parser.parse()parsedatetime.Calendar.parse() 的组合从用户那里获取datetime.datetime()。如果dateutil 失败,那么我尝试使用parsedatetime。用户学习如何输入日期和时间以使其正确识别。

【讨论】:

以上是关于如何将描述时间的字符串转换为秒?的主要内容,如果未能解决你的问题,请参考以下文章

如何将“'n' min 'm' secs”转换为秒格式

将字符串类型的时间转换为秒

如何将mm:ss时间字符串转换为秒整数(postgres / liquibase)

如何将 yyyy/MM/dd hh:mm:ss 转换为秒?

仅在 javascript 中将 HH:MM:SS 字符串转换为秒

Python实现ParseDuration-支持解析字符串格式的时间单位,例如将小时或者分钟数转换为秒