In my app I need to be able to find all number substrings, then scan each one, find the first one that matches a range (such as between 5 and 15) and replace THAT instance with another string "X".
My test string s = "1 foo 100 bar 10 gee 1"
My initial pattern is any string of 1 or more digits, eg, re = Regexp.new(/\d+/)
matches = s.scan(re)
gives ["1", "100", "10", "1"]
If I want to replace the Nth match, and only the Nth match, with "X" how do I?
For example if I want to replace the third match "10" (matches[2]) I can't just say
s[matches[2]] = "X"
because that does two replacements
"1 foo X0 bar X gee 1"
Any help would be appreciated!
String#gsub
has a form that takes a block. It yields to the block for each match, and replaces the match with the result of the block. So:
first = true
"1 foo 100 bar 10 gee 1 12".gsub(/\d+/) do |digits|
number = digits.to_i
if number >= 5 && number <= 15 && first
# do the replacement
first = false
'X'
else
# don't replace; i.e. replace with itself
digits
end
end
# => "1 foo 100 bar X gee 1 12"
An alternate way is to construct number range using character class (if it is not too complicated)
>> s = "1 foo 100 bar 10 gee 1"
=> "1 foo 100 bar 10 gee 1"
>> s.sub(/(?<!\d)([5-9]|1[0-5])(?!\d)/, 'X')
=> "1 foo 100 bar X gee 1"
\b
instead of lookarounds if the numbers cannot be part of words like abc12ef
or 8foo
([5-9]|1[0-5])
will match numbers from 5 to 15
Initially, the title lead me to think that you want to replace Nth occurrence - for ex: N=2 means replace second occurrence of any digit sequence. For that you can use this:
# here the number inside {} will be N-1
>> s.sub(/(\d+.*?){1}\K\d+/, 'X')
=> "1 foo X bar 10 gee 1"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With