Deleting a substring from a string in Ruby - ruby

For destructively deleting substrings from a string by match with a regex or a string (not a character range used for tr), there is one way to do it:
string.gsub!(regex_or_string_pattern, "")
string # => ...
I thought this can be replaced by the following code:
string.slice!(regex_or_string_pattern)
string # => ...
However, testing them with some examples seem to indicate that they are not equivalent. When do they end up with different results?

Because gsub! is "Global Substitution". If there are more than one matches to your string_or_regex_pattern, gsub will replace all of them with "". However slice! will only slice out the first match.

Related

How do I specify in Ruby that I want to match a character provided that a sequence following that character does not match a pattern?

I'm using Ruby on Rails 5.1. In Ruby, how do I say taht I want to match a string if the first character matches something but the sequence that follows does NOT match a pattern? That is, I want to match a number provided that the sequence taht follows is not a character from an array I have followed by two other numbers. Here's my character array ...
2.4.0 :010 > TOKENS
=> [":", ".", "'"]
So this string would NOT match
3:00
since ":00" matches the pattern of a character from my array followed by two numbers. But this string
3400
would match. This string would also match
3:0
and this would match
3
since nothing follows the above. How do I write the appropriate regex in Ruby?
string =~ /\A\d+(?!:\d{2})/
This regular expression means:
\A anchors the match to the start of the string.
\d+ means "one or more digits".
(?!...) is a negative look-ahead. It checks that the pattern contained in the brackets does not match., looking ahead from the current position.
:\d{2} means : followed by two digits.
Consideration should be given to testing the first character and the remaining characters separately.
def match_it?(str, first_char_regex, no_match_regex)
str[0].match?(first_char_regex) && !str[1..-1].match?(no_match_regex)
end
match_it?("0:00", /0/, /\A[:. ]cat\z/) #=> true
match_it?("0:00", /\d/, /\A[:. ]\d+\z/) #=> false
match_it?("0:00", /[[:alpha:]]/, /\A[:. ]\d+\z/) #=> false
I believe this reads well and it simplifies testing when compared to methods that employ a single regular expression.

How in ruby delete all non-digits symbols (except commas and dashes)

I meet some hard task for me. I has a string which need to parse into array and some other elements. I have a troubles with REGEXP so wanna ask help.
I need delete from string all non-digits, except commas (,) and dashes (-)
For example:
"!1,2e,3,6..-10" => "1,2,3,6-10"
"ffff5-10...." => "5-10"
"1.2,15" => "12,15"
and so.
[^0-9,-]+
This should do it for you.Replace by empty string.See demo.
https://regex101.com/r/vV1wW6/44
We must have at least one non-regex solution:
def keep_some(str, keepers)
str.delete(str.delete(keepers))
end
keep_some("!1,2e,3,6..-10", "0123456789,-")
#=> "1,2,3,6-10"
keep_some("ffff5-10....", "0123456789,-")
#=> "5-10"
keep_some("1.2,15", "0123456789,-")
#=> "12,15"
"!1,2e,3,6..-10".gsub(/[^\d,-]+/, '') # => "1,2,3,6-10"
Use String#gsub with a pattern that matches everything except what you want to keep, and replace it with the empty string. In a reguar expression, the negated character class [^whatever] matches everything except the characters in the "whatever", so this works:
a_string.gsub /[^0-9,-]/, ''
Note that the hyphen has to come last, as otherwise it will be interpreted as a range indicator.
To demonstrate, I put all your "before" strings into an Array and used Enumerable#map to run the above gsub call on all of them, producing an Array of the "after" strings:
["!1,2e,3,6..-10", "ffff5-10....", "1.2,15"].map { |s| s.gsub /[^0-9,-]/, '' }
# => ["1,2,3,6-10", "5-10", "12,15"]

regex for a pattern at end of string

I have a string which looks like:
hello/world/1.9.2-some-text
hello/world/2.0.2-some-text
hello/world/2.11.0
Through regex I want to get the string after last '/' and until end of line i.e. in above examples output should be 1.9.2-some-text, 2.0.2-some-text, 2.11.0
I tried this - ^(.+)\/(.+)$ which returns me an array of which first object is "hello/world" and 2nd object is "1.9.2-some-text"
Is there a way to just get "1.9.2-some-text" as the output?
Try using a negative character class ([^…]) like this:
[^\/]+$
This will match one or more of any character other than / followed by the end of the string.
You can use a negated match here.
'hello/world/1.9.2-some-text'.match(Regexp.new('[^/]+$'))
# => "1.9.2-some-text"
Meaning any character except: / (1 or more times) followed by the end of the string.
Although, the simplest way would be to split the string.
'hello/world/1.9.2-some-text'.split('/').last
# => "1.9.2-some-text"
OR
'hello/world/1.9.2-some-text'.split('/')[-1]
# => "1.9.2-some-text"
If you do not need to use a regex, the ordinary way of doing such thing is:
File.basename("hello/world/1.9.2-some-text")
#=> "1.9.2-some-text"
This is one way:
s = 'hello/world/1.9.2-some-text
hello/world/2.0.2-some-text
hello/world/2.11.0'
s.lines.map { |l| l[/.*\/(.*)/,1] }
#=> ["1.9.2-some-text", "2.0.2-some-text", "2.11.0"]
You said, "in above examples output should be 1.9.2-some-text, 2.0.2-some-text, 2.11.0". That's neither a string nor an array, so I assumed you wanted an array. If you want a string, tack .join(', ') onto the end.
Regex's are naturally "greedy", so .*\/ will match all characters up to and including the last / in each line. 1 returns the contents of the capture group (.*) (capture group 1).

String containment

Is there a way to check in Ruby whether the string "1:/2" is contained within a larger string str, beside iterating over all positions of str?
You can use the include? method
str = "wdadwada1:/2wwedaw"
# => "wdadwada1:/2wwedaw"
str.include? "1:/2"
# => true
A regular expression will do that.
s =~ /1:\/2/
This will return either nil if s does not contain the string, or the integer position if it does. Since nil is falsy and an integer is truthy, you can use this expression in an if statement:
if s =~ /1:\/2/
...
end
The regular expression is normally delimited by /, which is why the slash within the regular expression is escaped as \/
It is possible to use a different delimiter to avoid having to escape the /:
s =~ %r"1:/2"
You could use other characters than " with this syntax, if you want.
The simplest and most straight-forward is to simply ask the string if it contains the sub-string:
"...the string 1:/2 is contained..."['1:/2']
# => "1:/2"
!!"...the string 1:/2 is contained..."['1:/2']
# => true
The documentation has the full scoop; Look at the last two examples.

How can I replace every instance of a pattern in ruby?

string.sub looks like it only replaces the first instance. Is there an option for that or another method that can replace all patterns? Can you do it inside a regex like perl?
(I think something like r/blah/blah/)
... and +1 to anyone who can tell me WHY ON EARTH does string.sub replace just the FIRST match?
String.gsub should do the trick.
Quoting docs:
gsub(pattern, replacement) → new_str
Returns a copy of str with the all occurrences of pattern
substituted for the second argument. The pattern is typically a
Regexp; if given as a String, any regular expression metacharacters it
contains will be interpreted literally, e.g. \\d will match a
backlash followed by d, instead of a digit.
I could explain why sub just replaces the first match of a pattern, but I think the documentation does it so much better (from ri String#sub on the command line):
str.sub(pattern, replacement) => new_str
str.sub(pattern) {|match| block } => new_str
Returns a copy of _str_ with the _first_ occurrence of _pattern_
replaced with either _replacement_ or the value of the block.

Resources