How to split a string which contains multiple forward slashes - ruby

I have a string as given below,
./component/unit
and need to split to get result as component/unit which I will use this as key for inserting hash.
I tried with .split(/.\//).last but its giving result as unit only not getting component/unit.

I think, this should help you:
string = './component/unit'
string.split('./')
#=> ["", "component/unit"]
string.split('./').last
#=> "component/unit"

Your regex was almost fine :
split(/\.\//)
You need to escape both . (any character) and / (regex delimiter).
As an alternative, you could just remove the first './' substring :
'./component/unit'.sub('./','')
#=> "component/unit"

All the other answers are fine, but I think you are not really dealing with a String here but with a URI or Pathname, so I would advise you to use these classes if you can. If so, please adjust the title, as it is not about do-it-yourself-regexes, but about proper use of the available libraries.
Link to the ruby doc:
https://docs.ruby-lang.org/en/2.1.0/URI.html
and
https://ruby-doc.org/stdlib-2.1.0/libdoc/pathname/rdoc/Pathname.html
An example with Pathname is:
require 'pathname'
pathname = Pathname.new('./component/unit')
puts pathname.cleanpath # => "component/unit"
# pathname.to_s # => "component/unit"
Whether this is a good idea (and/or using URI would be cool too) also depends on what your real problem is, i.e. what you want to do with the extracted String. As stated, I doubt a bit that you are really intested in Strings.

Using a positive lookbehind, you could do use regex:
reg = /(?<=\.\/)[\w+\/]+\w+\z/
Demo
str = './component'
str2 = './component/unit'
str3 = './component/unit/ruby'
str4 = './component/unit/ruby/regex'
[str, str2, str3, str4].each { |s| puts s[reg] }
#component
#component/unit
#component/unit/ruby
#component/unit/ruby/regex

Related

opposite of sub in ruby

I want to replace the content (or delete it) that does not match with my filter.
I think the perfect description would be an opposite sub. I cannot find anything similar in the docs, and I'm not sure how to invert the regex, but I think a method would probably be the more convenient.
An example of how it would work (I've just changed the words to make it more clear)
"bird.cats.dogs".opposite_sub(/(dogs|cats)\.(dogs|cats)/, '')
#"cats.dogs"
I hope it's easy enough to understand.
Thanks in advance.
String#[] can take a regular expression as its parameter:
▶ "bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#⇒ "cats.dogs"
For multiple matches one can use String#scan:
▶ "bird.cats.dogs.bird.cats.dogs".scan /(?:dogs|cats)\.(?:dogs|cats)/
#⇒ ["cats.dogs", "cats.dogs"]
So you want to extract the part that matches your regex?
You can use String#slice, for example:
"bird.cats.dogs".slice(/(dogs|cats)\.(dogs|cats)/)
#=> "cats.dogs"
And String#[] does the same.
"bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#=> "cats.dogs"
You cannot have a single replacement string because the part of the string that matches the regex might not be at the beginning or end of the string, in which case it's not clear whether the replacement string should precede or follow the matching string. I've therefore written the following with two replacement strings, one for pre-match, the other for post_match. I've made this a method of the String class as that's what you've asked for (though I've given the method a less-perfect name :-) )
class String
def replace_non_matching(regex, replace_before, replace_after)
first, match, last = partition(regex)
replace_before + match + replace_after
end
end
r = /(dogs|cats)\.(dogs|cats)/
"birds.cats.dogs.pigs".replace_non_matching(r, "", "")
#=> "cats.dogs"
"birds.cats.dogs".replace_non_matching(r, "snakes.", ".hens")
#=> "snakes.cats.dogs.hens"
"birds.cats.dogs.mice.cats.dogs.bats".replace_non_matching(r, "snakes.", ".hens")
#=> "snakes.cats.dogs.hens"
Regarding the last example, the method could be modified to replace "birds.", ".mice." and ".bats", but in that case three replacement strings would be needed. In general, determining in advance the number of replacement strings needed could be problematic.

Ruby - Deleting every word from an array

In my app, I have to monitor what users type. So I have to prevent any bad words from the web site. Just for example, suppose all my bad words were in this array.
bad_words = ['bad', 'evil', 'terrible', 'villain', 'enemy']
If a user typed those, I would like them to be deleted. Here was one thing I tried.
bad_words.each {|word| string.gsub(word, '')}
Help is appreciated.
You can use a Gem to do the clean job:
https://github.com/tjackiw/obscenity
including the gem will allow you methods like:
Obscenity.configure { |config| config.whitelist = bad_words }
and then:
Obscenity.sanitize(string)
Here's one way:
bad_words = ['bad', 'evil', 'terrible', 'villain', 'enemy']
orig_str =
"Evil is embodied by a terrible villain named 'Bad' who plays badmitten"
no_bad_str = orig_str.gsub(/(?<=^|\W)\w+(?=\W|$)/) { |w|
(bad_words.include?(w.downcase)) ? '' : w }
#=> " is embodied by a named '' who plays badmitten"
(?<=^|\W) is a positive lookbehind
(?=\W|$) is a positive lookahead
Can bad, evil and terrible words sneak by? Of course. Some examples for orig_str:
badbadbad
evilterribleenemy
eviloff
flyingevil
Good luck!
You can either do
bad_words.each {|word| string = string.gsub(word, '')}
or
bad_words.each {|word| string.gsub!(word, '')}
Either should work issue with your original was that it was returning a new string not modifying the old one like the to solutions I have proposed above.
You can use Regexp.union to create a regular expression containing all the words in yours list:
bad_words = ['bad', 'evil', 'terrible', 'villain', 'enemy']
Regexp.union(bad_words)
# => /bad|evil|terrible|villain|enemy/
string.gsub(Regexp.union(bad_words), '')

String#delete ignore special characters

String#delete interprets a-z as character range. However, I would like it to delete fa-zo.
"fojwfa-zowj".delete("fa-zo") #=> "-"
Desired result:
"fojwwj"
You could also use this little trick:
string = "fojwfa-zowj"
string[/fa-zo/] = ''
string
# => "fojwwj"
Notice however, that this modifies the string in place like #gsub!, which should be faster and should use less memory, but which could introduce side-effects if not considered well.
"fojwfa-zowj".gsub("fa-zo","") # => "fojwwj"
"fojwfa-zowj".tap{ |s| s.slice! "fa-zo" } # just for the Heaven of it

English Sentence to Camel-cased method name

I had to convert a series of sentences into camel-cased method names. I ended writing something for it. I am still curious if there's something simpler for it.
Given the string a = "This is a test." output thisIsATest
I used for following:
a.downcase.gsub(/\s\w/){|b| b[-1,1].upcase }
Not sure it's better as your solution but it should do the trick:
>> "This is a test.".titleize.split(" ").join.camelize(:lower)
=> "thisIsATest."
titleize: uppercase every first letter of each word
split(" ").join: create an array with each word and join to squeeze the spaces out
camelize(:lower): make the first letter lowercase
You can find some more fun functions in the Rails docs: http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html
"active_record".camelize(:lower)
output : "activeRecord"
use these
"Some string for you".gsub(/\s+/,'_').camelize(:lower) #=> "someStringForYou"
gsub: Replace spaces by underscores
camelize: java-like method camelcase
You might try using the 'English' gem, available at http://english.rubyforge.org/
require 'english/case'
a = "This is a test."
a.camelcase().uncapitalize() # => 'thisIsATest

Remove character from string if it starts with that character?

How can I remove the very first "1" from any string if that string starts with a "1"?
"1hello world" => "hello world"
"112345" => "12345"
I'm thinking of doing
string.sub!('1', '') if string =~ /^1/
but I' wondering there's a better way. Thanks!
Why not just include the regex in the sub! method?
string.sub!(/^1/, '')
As of Ruby 2.5 you can use delete_prefix or delete_prefix! to achieve this in a readable manner.
In this case "1hello world".delete_prefix("1").
More info here:
https://blog.jetbrains.com/ruby/2017/10/10-new-features-in-ruby-2-5/
https://bugs.ruby-lang.org/issues/12694
'invisible'.delete_prefix('in') #=> "visible"
'pink'.delete_prefix('in') #=> "pink"
N.B. you can also use this to remove items from the end of a string with delete_suffix and delete_suffix!
'worked'.delete_suffix('ed') #=> "work"
'medical'.delete_suffix('ed') #=> "medical"
https://bugs.ruby-lang.org/issues/13665
I've answered in a little more detail (with benchmarks) here: What is the easiest way to remove the first character from a string?
if you're going to use regex for the match, you may as well use it for the replacement
string.sub!(%r{^1},"")
BTW, the %r{} is just an alternate syntax for regular expressions. You can use %r followed by any character e.g. %r!^1!.
Careful using sub!(/^1/,'') ! In case the string doesn't match /^1/ it will return nil. You should probably use sub (without the bang).
This answer might be more optimised: What is the easiest way to remove the first character from a string?
string[0] = '' if string[0] == '1'
I'd like to post a tiny improvement to the otherwise excellent answer by Zach. The ^ matches the beginning of every line in Ruby regex. This means there can be multiple matches per string. Kenji asked about the beginning of the string which means they have to use this regex instead:
string.sub!(/\A1/, '')
Compare this - multiple matches with this - one match.

Resources