String tools in ruby

Asked

Viewed 178 times

1

Suppose the following string: "acc5???7???7ss?3rr1???5".

How to check if the three question marks exist (exactly three) and if they are before or after numbers that add up to more than 10?

I thought I’d split us ???, but I get lost from there.

teste = "acc5???7???7ss?3rr1??5"

clean = "???"


var = teste.split(clean)
puts "#{var}"

1 answer

1


An alternative is to use the method scan, passing a regular expression (regex):

teste = "acc5???7???7ss?3rr1??5"
var = teste.scan(/(?<=\?{3})\d+|\d+(?=\?{3})/).map(&:to_i).reduce(:+)

puts "#{var}" # 19
if var > 10
    puts "valor maior que 10"
else
    puts "valor menor ou igual a 10"
end

The regex is (?<=\?{3})\d+|\d+(?=\?{3}) (the bars at the beginning and end serve only to delimit the regex, but are not part of it). Explaining:

She uses alternation (the character |), meaning "or". This means that regex has 2 possibilities.

The first is (?<=\?{3})\d+:

  • \d+ corresponds to "one or more digits"
  • the stretch within (?<= ... ) is a lookbehind; it serves to check if something exists before the current position. In this case, this "something" is \?{3} (exactly 3 occurrences of the question mark)

That is, this section looks for one or more digits, provided they have 3 question marks immediately before.

The second possibility is \d+(?=\?{3}), and is similar to the first. We have one or more digits (\d+), and now we have a Lookahead, which checks if something exists ahead (and in the case, the "something" is also "3 question marks").

That is, regex takes one or more digits, but only if you have the 3 question marks before or after.

The method scan returns an array with the captured digits. But regex only works with text, so these digits (in this case, 5 and 7) are returned as strings.

So I use map to turn them into numbers (through to_i), and then use reduce to add them up. Then just see if the result is greater than 10.


Heed

The above regex also takes numbers that have more than 3 question marks before or after (see). If you want exactly 3, you have to increase the regex a little more:

var = teste.scan(/(?<=[^\?]\?{3})\d+|\d+(?=\?{3}(?:[^\?]|$))/).map(&:to_i).reduce(:+)

I added [^\?], which is "any character other than the ?", so it doesn’t pick up the digits if there are more than 3 question marks before or after (see the difference).

  • 1

    Excellent resolution, regex is really a powerful tool. I need to practice more. Thanks!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.