简体   繁体   中英

Ruby: Split string at character, counting from the right side

Short version -- How do I do Python rsplit() in ruby?

Longer version -- If I want to split a string into two parts (name, suffix) at the first '.' character, this does the job nicely:

name, suffix = name.split('.', 2)

But if I want to split at the last (rightmost) '.' character, I haven't been able to come up with anything more elegant than this:

idx = name.rindex('.')
name, suffix = name[0..idx-1], name[idx+1..-1] if idx

Note that the original name string may not have a dot at all, in which case name should be untouched and suffix should be nil; it may also have more than one dot, in which case only the bit after the final one should be the suffix.

String#rpartition does just that:

name, match, suffix = name.rpartition('.')

It was introduced in Ruby 1.8.7, so if running an earlier version you can use require 'backports/1.8.7/string/rpartition' for that to work.

Put on the thinking cap for a while and came up with this regexp:

"what.to.do.now".split(/\.([^.]*)$/)
=> ["what.to.do", "now"]

Or in human terms "split at dot, not followed by another dot, at end of string". Works nicely also with dotless strings and sequences of dots:

"whattodonow".split(/\.([^.]*)$/)
=> ["whattodonow"]
"what.to.do...now".split(/\.([^.]*)$/)
=> ["what.to.do..", "now"]

Here's what I'd actually do:

/(.*)\.(.*)/.match("what.to.do")[1..2]
=> ["what.to", "do"]

or perhaps more conventionally,

s = "what.to.do"

s.match(/(.*)\.(.*)/)[1..2]
=> ["what.to", "do"]

if this="what.to.do" you can do this:

this.split(%r{(.+)\.})

and you'll get back

["", "what.to", "do"]

If you want the literal version of rsplit , you can do this (this is partly a joke, but actually works well):

"what.to.do".reverse.split('.', 2).map(&:reverse).reverse
=> ["what.to", "do"]

You can also add rsplit to the String class by adding this at the top of your file.

class String
  def rsplit(pattern=nil, limit=nil)
    array = self.split(pattern)
    left = array[0...-limit].join(pattern)
    right_spits = array[-limit..]
    return [left] + right_spits
  end
end

It doesn't quite work like split. eg

$ pry
[1] pry(main)> s = "test.test.test"
=> "test.test.test"
[2] pry(main)> s.split('.', 1)
=> ["test.test.test"]
[3] pry(main)> s.split('.', 2)
=> ["test", "test.test"]
[4] pry(main)> s.split('.', 3)
=> ["test", "test", "test"]

vs.

[6] pry(main)> s
=> "test.test.test"
[7] pry(main)> s.rsplit('.', 1)
=> ["test.test", "test"]
[8] pry(main)> s.rsplit('.', 2)
=> ["test", "test", "test"]

But I can't quite work out how to short split it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM