将基于时间的字符串转换为ISO格式

3

我有一个名为Song的对象,它有一个时长属性(基于字符串),以分钟和秒为单位。我想将其输出为<time/>标签的datetime属性(通过Rails),但需要将其转换为ISO 8601格式,以使其在语义上有效。

所以,我有一个时长为"2:30"的字符串。需要在两个数字之间去掉冒号并在最后附加字母'S',同时在开头添加字符'PT'

PT2M30S

最终输出:
<time itemprop="duration" datetime="PT2M30S">2:30</time>

我该如何完成这个任务?
有没有现成的 Ruby 方法可以实现这个任务?还是必须编写正则表达式来查找/替换上述字符?
3个回答

2
如果你想以优雅的方式完成它,可以尝试使用 ruby-duration gem。
示例代码:
Duration.new(:weeks => 1, :days => 20).iso8601 => "P3W6DT0H0M0S"

2

不需要使用正则表达式或任何高级技巧来完成这个任务。我会简单地按冒号进行分割,并将结果传递给一个格式化字符串:

'PT%sM%sS' % "2:30".split(':') # => "PT2M30S"

在这种情况下,取模运算符如何工作?我以前从未见过这样的操作。
除非应用于数字,否则它不是“取模运算符”。它是一个名为“%”的字符串方法,相当于“format”或“sprintf”。有关更多信息,请参见String.%,然后是Kernel::sprintf,但基本上:
  s   | Argument is a string to be substituted.  If the format
      | sequence contains a precision, at most that many characters
      | will be copied.

所以:
'%s'   % 'foo' # => "foo"
'%5s'  % 'foo' # => "  foo"
'%-5s' % 'foo' # => "foo  "
'%1s'  % 'foo' # => "foo"
'%.1s' % 'foo' # => "f"

'%s = %s' % ['a', 1] # => "a = 1"

特别说明,在最后一个示例中,当将1插入字符串时会被转换为"1"。这种方式可以很有用,但并非将对象转换为字符串的唯一或者最好的方式。
最后,不要假设正则表达式是从字符串中提取信息的每个问题的最佳解决方法。如果你可以避免使用奇怪的变通方法,就使用内置的方法,例如split
require 'fruity'

compare do
  _split { 'PT%sM%sS' % "2:30".split(':') }
  _regex { "2:30".sub(/(.*):(.*)/, "PT\\1M\\2S") }
end

这导致:
# >> Running each test 2048 times. Test will take about 1 second.
# >> _split is faster than _regex by 19.999999999999996% ± 10.0%

正则表达式灵活,但通常代价是更慢。

此外,我们看到许多误用gsub而应该使用sub的情况。相比之下,sub的工作量要少得多;当sub触发一次时,gsub将继续循环直到达到字符串的末尾。即使在如"2:30"这样的短字符串上也有可测量的差异:

compare do
  _sub { "2:30".sub(/(.*):(.*)/, "PT\\1M\\2S") }
  _gsub { "2:30".gsub(/(.*):(.*)/, "PT\\1M\\2S") }
end

# >> Running each test 2048 times. Test will take about 1 second.
# >> _sub is faster than _gsub by 2x ± 0.1

在这种情况下,取模运算符如何工作?以前从未见过类似的做法。 - Carl Edwards
请查看添加的内容。 - the Tin Man
再次感谢您,非常感激详细的解释。 - Carl Edwards

1
我会将这个转化为一个方法...
> "2:30".sub(/(.*):(.*)/, "PT\\1M\\2S")
=> "PT2M30S"

谢谢您提供答案。只有一个问题。在sub()方法的第二个参数中,这两个反斜杠代表什么?请原谅我,我的正则表达式水平还不够。 - Carl Edwards
\1\2 表示匹配捕获的值,但由于它们位于双引号内,因此需要加倍。 在这种情况下,\\ 是一个字面上的反斜杠字符。 - tadman
1
请看一下我回答末尾的简单基准测试。过早地使用正则表达式可能会很昂贵。在考虑使用它们时要有辨别力。 - the Tin Man

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接