当我在方法中使用保护案例时sum_time一个测试用例失败了,有什么建议吗?



>编写一个汇总多个 24 小时时间值 (h:m:s) 的方法。 使用正则表达式验证时间。

输入和输出格式: 例如:"11:23:07","22:53:45","0:23:23","23:45:56") -> "2 天 & 10:26:11" ("11:23:07") -> "11:23:07">

我的代码在一个测试用例中失败,即 "24:01:10" "10:30:50">

溶液:

require 'time'
# Time_Sum
class Time
KEY = /^(0d|1d|2[0-3]|d):[0-5]d?:[0-5]d?$/
def to_seconds(timestamp)
timestamp.hour * 3600 + timestamp.min * 60 + timestamp.sec
end
def validate?(time_string)
time_string.match(KEY)
end
def sum_time(*time)
total_seconds = 0
time.each do |time_item|
timestamp = Time.parse(time_item) if validate?(time_item)
total_seconds += to_seconds(timestamp) if validate?(time_item)
'Invalid 24-hour time value'
end
display_results(total_seconds)
end
def display_results(total_seconds)
sum_time_string = ''
days = (total_seconds / (24 * 3600)).to_i
sum_time_string = "#{days} day & " if days > 0
sum_time_string + Time.at(total_seconds).utc.strftime('%H:%M:%S')
end
end
reader = Time.new
if ARGV.empty?
puts 'Please provide an input'
else
p reader.sum_time(*ARGV)
end

预期输出 : "无效的 24 小时时间值" 实际输出 : "10:30:50">

还有人可以建议更好的正则表达式密钥吗?

首先,我建议不要污染核心 Ruby 类Time。所需的方法可以放在自定义类中,也可以在main级别定义(如下所述)。

我也不会使用类TimeDateTime。只处理字符串更容易。首先构造一个正则表达式,该表达式将用于确定每个时间字符串是否有效。

VALID_TIME = /
A        # match beginning of string
(?:       # begin non-capture of group
0?d    # optionally match a zero followed by a digit
|       # or
1d     # match 1 followed by a digit
|       # or
2[0-3]  # match 2 followed by a digit 0, 1, 2 or 3
)         # end non-capture group
(?:       # begin a non-capture group
:       # match a colon
[0-5]   # match a digit 0, 1, 2, 3, 4 or 5
d      # match a digit
)         # end non-capture group
{2}       # execute the previous non-capture group twice
/x        # free-spacing regex-definition mode

在自由间距模式下编写正则表达式的优点是使它们能够自我记录。此正则表达式通常编写如下:

/A(?:0?d|1d|2[0-3])(?::[0-5]d){2}/

我们的主要方法可能是total_times,向其传递一个或多个表示二十四小时时间的字符串。

def total_times(*time_strings)
seconds    = tot_seconds(*time_strings)
days, hrs  = seconds.divmod(24*3600)
hrs,  mins = hrs.divmod(3600)
mins, secs = mins.divmod(60)
[days, hrs, mins, secs]
end

这首先调用一个方法tot_seconds,具有相同的参数。该方法返回自午夜以来每次经过的秒数的总和。获得总秒数后,重复使用 Integer#divmod 来计算等效的天数、小时数、分钟数和秒数。

def tot_seconds(*time_strings)
time_strings.sum { |time_str| time_str_to_seconds(time_str) }
end

此方法将每个时间字符串传递给方法time_str_to_seconds,该方法返回该时间字符串自午夜以来的秒数。

def time_str_to_seconds(time_str)
raise ArgumentError, "'#{time_str}' is an invalid 24-hour time value" unless
time_str.match?(VALID_TIME)
[3600, 60, 1].zip(time_str.split(':')).
reduce(0) { |tot,(n,s)| tot + n*s.to_i }
end

此方法首先检查时间字符串的有效性。如果发现无效,则会引发异常。这似乎是进行有效性检查的最佳位置。如果发现字符串有效,则将其拆分为表示小时、分钟和秒的字符串,然后将其转换为整数并组合以获得秒数。

假设:

time_str = "9:35:08"

那么time_str_to_seconds计算如下:

time_str.match?(VALID_TIME)
#=> true
a = time_str.split(':')
#=> ["9", "35", "08"] 
b = [3600, 60, 1].zip(a)
#=> [[3600, "9"], [60, "35"], [1, "08"]]
b.reduce(0) { |tot,(n,s)| tot + n*s.to_i }
#=> 3600*9 + 60*35 + 1*8 => 34508

请参阅 String#match? 和 Array#zip。

现在让我们通过一个例子来尝试一下。

arr = total_times "2:33:41", "23:46:08"
#=> [1, 2, 19, 49]

我们可以按如下方式使用这些结果:

puts "%d day & %d:%2d:%2d" % arr
"1 day & 2:19:49"

在某些情况下,最好写:

days, hrs, mins, secs = total_times "2:33:41", "23:46:08"

我们可以很容易地确认这些结果。

tot_secs =  2*3600 + 33*60 + 41 +
23*3600 + 46*60 +  8
#=> 94789 
days, hrs  = tot_secs.divmod(24*3600)
#=> [1, 8389] 
hrs, mins  = hrs.divmod(3600)
#=> [2, 1189] 
mins, secs = mins.divmod(60)
#=> [19, 49] 
[days, hrs, mins, secs] 
#=> [1, 2, 19, 49] 

另外两个例子:

total_times "11:23:07", "22:53:45", "0:23:23", "23:45:56"
#=> [2, 10, 26, 11]
total_times "24:01:10", "10:30:50"
#=> ArgumentError ('24:01:10' is an invalid 24-hour time value)

请注意,不必使用正则表达式来确定时间字符串的有效性。可以这样写:

time_str = "9:35:08"
hr, min, sec = time_str.split(':').map(&:to_i)
#=> [9, 35, 8] 
(0..23).cover?(hr) && (0..59).cover?(min) && (0..59).cover?(sec)
#=> true

相关内容

最新更新