2

我需要解析代表时间段的字符串的内容。字符串的格式为值/单位,例如:1s、60min、24h。我会将实际值(一个 int)和单位(一个 str)分隔为单独的变量。

目前我这样做:

def validate_time(time):
    binsize = time.strip()
    unit = re.sub('[0-9]','',binsize)
    if unit not in ['s','m','min','h','l']:
        print "Error: unit {0} is not valid".format(unit)
        sys.exit(2)
    tmp = re.sub('[^0-9]','',binsize)
    try:
        value = int(tmp)
    except ValueError:
        print "Error: {0} is not valid".format(time) 
        sys.exit(2)
    return value,unit

但是,它并不理想,因为像 1m0 这样的东西也(错误地)被验证(value=10unit=m)。

验证/解析此输入的最佳方法是什么?

4

3 回答 3

2

只需用一个正则表达式解析整行:

_timeunit = re.compile(r'^(?P<value>\d+)(?P<unit>s|m|min|h|l)$')
def validate_time(time):
    match = _timeunit.match(time.strip())
    if match is None:
        print "Error: {0} is not valid".format(time)
        sys.exit(2)

    return int(match.group('value')), match.group('unit')

演示(将 sys.exit 暂时替换为 return):

>>> validate_time('10l')
(10, 'l')
>>> validate_time('10l0')
Error: 10l0 is not valid

正则表达式匹配开头的数字(由^插入符号匹配),然后是有限集合中的单位s, m,或min,但前提是它们位于行尾,由美元符号匹配。hl$

顺便说一句,在验证方法中引发异常并在调用该方法的地方处理该异常会更加pythonic。这使它更具可重用性:

_timeunit = re.compile(r'^(?P<value>\d+)(?P<unit>s|m|min|h|l)$')
def validate_time(time):
    match = _timeunit.match(time.strip())
    if match is None:
        raise ValueError('{0} is not a valid timespan'.format(time))    
    return int(match.group('value')), match.group('unit')

try:
    validate_time(foobar)
except ValueError, e:
    print 'Error: {0}'.format(e.args[0])
    sys.exit(2)
于 2012-09-06T16:15:28.127 回答
0

为什么不一次性解析它:

m = re.match(r'(?P<value>\d+)\s*(?P<unit>\w+)',time.strip())
#              #^number
#                            #^spaces (optional) 
#                               #^non-number
if not m:
   pass #error

if m.group(0) != time.strip():
   pass #error -- leftover stuff at the end.  This will catch '1m0'

unit = m.group('unit')
value = int(m.group('value'))
于 2012-09-06T15:36:00.503 回答
0

试试这个:

#!/usr/bin/env python

import re

time = '1m'
try:
  m = re.match(r'^(?P<value>\d+)(?P<middle>.*)(?P<unit>(m|min|s|h|l))$',
    time.strip())
  value = m.group('value')
  unit = m.group('unit')
  middle = m.group('middle')
  if middle :
    # Reuse the exception raised if an expected group is not found
    raise AttributeError
  print value, unit
except AttributeError:
  print "Wrong format"

它确保时间以数字开始,以有效单位结束,并在中间捕获任何内容。

于 2012-09-06T16:10:41.353 回答