Issue
I have an Song
object that has a duration attribute (string based) that goes by minutes and seconds. I want to output this as a datetime
attribute for a <time/>
tag (via Rails) but needed to convert it to ISO 8601 format in order for it to be semantically valid.
So, I have the duration, "2:30"
. The characters 'PT'
would need to be prepended while removing the colon in between the two numbers and finally appending the letter 'S'
at the end:
PT2M30S
Final output:
<time itemprop="duration" datetime="PT2M30S">2:30</time>
How would I go about in accomplishing this?
Is there a Ruby method that accomplishes this already? Does a regular expression have to be written out in order to find/replace the aforementioned characters?
Solution
It doesn't take a regex or anything fancy to do this. I'd simply split on the colon, and pass the result into a format string:
'PT%sM%sS' % "2:30".split(':') # => "PT2M30S"
How does the modulo operator work in this case? Never seen something done like this before.
It's not the "modulo operator" unless it's being applied to a number. It's a String method named %
that is an equivalent to format
or sprintf
. See String.%
followed by Kernel::sprintf
for more information, but basically:
s | Argument is a string to be substituted. If the format
| sequence contains a precision, at most that many characters
| will be copied.
So:
'%s' % 'foo' # => "foo"
'%5s' % 'foo' # => " foo"
'%-5s' % 'foo' # => "foo "
'%1s' % 'foo' # => "foo"
'%.1s' % 'foo' # => "f"
'%s = %s' % ['a', 1] # => "a = 1"
In particular, note that in the last one 1
is converted to "1"
when inserted into the string. This can be useful but it isn't the only way, (or even a preferable way) to convert from an object to a string.
Finally, don't assume regular expressions are the way to go for every problem requiring extracting information from a string. If you can do it without resorting to weird work-arounds, use the built-in methods, like split
:
require 'fruity'
compare do
_split { 'PT%sM%sS' % "2:30".split(':') }
_regex { "2:30".sub(/(.*):(.*)/, "PT\\1M\\2S") }
end
Which results in:
# >> Running each test 2048 times. Test will take about 1 second.
# >> _split is faster than _regex by 19.999999999999996% ± 10.0%
Regular expressions are flexible but that usually comes at the price of being slower.
Also, we see a lot of misuse of gsub
when sub
should be used. sub
does a lot less work than gsub
; Where sub
fires once, gsub
will continue to loop until it hits the end of the string. That is a measurable difference, even on a short string such as "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
Answered By - the Tin Man
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.