【问题标题】:Python: Time input validationPython:时间输入验证
【发布时间】:2015-04-30 07:11:10
【问题描述】:

我有休闲问题, 我应该以10:10:10 (hh:mm:ss) 或10:10(mm:ss) 或10(ss) 的形式获取用户输入。现在我需要检查休闲参数:

  • 如果我只有几秒钟,那么没有限制。
  • 如果我收到 mm:ss,则秒数限制为 0..59,分钟数无限制。
  • 如果我收到 hh:mm:ss,则秒数和分钟数都限制为 0..59,而小时数则不受限制。

然后返回一个 TimeDelta 对象。

天真的方法是编写乘法if 语句来检查所有这些。 但我正在寻找更顺畅的方式。

val = "11:66:11"
try:
    val = map(int, val.split(':'))
except ValueError:
    return False
if len(val) == 1:
    return val
if len(val) == 2:
    if val[1] > 59:
        print  "Bad seconds"
        return False
if len(val) == 3:
    if val[2] > 59 or val[1] >59:
        print  "Bad seconds / minutes"
        return False
while len(val) < 3:
        split.insert(0,0)
return = timedelta(hours=split[0],minutes=split[1],seconds=split[2])

【问题讨论】:

  • 你有什么错误吗?你面临什么问题?
  • 没有错误,我写的代码是做我想做的事情的本机方式。我要求更顺畅的方式。一种更 Pythonic 的方式。

标签: python python-2.7 date


【解决方案1】:

这里用正则表达式怎么样:

import re
import datetime
pattern = re.compile(r'^(\d+)(?::([0-5]?\d)(?::([0-5]?\d))?)?$')

def str2seconds(val):
    match = pattern.match(val)
    if not match:
        raise ValueError("Invalid input: %s" % val)
    else:
        result = 0
        for i in match.groups():
            if i is not None:
                result *= 60
                result += int(i)

    return datetime.timedelta(seconds=result)

例子:

>>> print(str2seconds('255'))
0:04:15
>>> print(str2seconds('255:25'))
4:15:25
>>> print(str2seconds('255:25:25'))
10 days, 15:25:25
>>> print(str2seconds('255:25:25:255'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "y.py", line 8, in str2seconds
    raise ValueError("Invalid input: %s" % val)
ValueError: Invalid input: 255:25:25:255
>>> print(str2seconds('255:25:60'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "y.py", line 8, in str2seconds
    raise ValueError("Invalid input: %s" % val)
ValueError: Invalid input: 255:25:60

部分正则表达式:

  • ^: 字符串开头
  • (\d+):1-n 位,作为第 1 组捕获
  • (?::([0-5]?\d)(?::([0-5]?\d))?)? 可选部分:
    • (?:...) 是非捕获组
    • : 匹配文字 :
    • ([0-5]?\d) 可选数字 0-5,后跟一个数字,捕获为第 2 组
    • 第一个中有第二个非捕获组: (?::([0-5]?\d))? 可选匹配第二个 : 后跟 可选数字 0-5,后跟数字;并将数字捕获到第 3 组
    • 最后$ 匹配字符串的结尾。严格来说,开头的^ 是不必要的,因为match 在开头锚定了比赛;但是 $ 是必需的,否则匹配不会锚定在字符串的末尾! (Python 3.4 添加了the re.fullmatch 来解决这个问题。)

match.groups() 将是 3 个项目的元组;不匹配的组将返回为None

【讨论】:

  • 像魅力一样工作!你能解释一下正则表达式吗?试图理解它,但有点卡住了。
  • 如果您尝试使用正则表达式解决问题,通常会遇到两个问题。我认为更基本的字符串分析更合适。
  • @AnttiHaapala 开什么玩笑?如果 OP 必须更改该正则表达式,他将很难。然而,使用更标准(如果可以的话,更详细)的方法,他或其他任何人现在或三年内都可以改变它。
  • 简单的正则表达式很简单。诚然,正则表达式可以用一些 cmets 以详细模式编写——如果可维护性是优先事项,那么无论如何你都会使用“标准详细方法”。
猜你喜欢
  • 1970-01-01
  • 2013-10-10
  • 2012-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-21
相关资源
最近更新 更多