If Statement in Ruby Using Regex

Using regex in Ruby if condition

if params[:test] =~ /foo/
# Successful match
else
# Match attempt failed
end

Works for me. Debug what is in params[:test]

Ruby: why does =~ evaluate to true in an if statement?

The predicate after if will be treated as a boolean value.

In Ruby, only false and nil are treated as false. Anything other will be evaluated to true, so 0, [], {} are all true in boolean context.

From Ruby doc:

nil and false are both false values. nil is sometimes used to indicate "no value" or "unknown" but evaluates to false in conditional expressions.

true is a true value. All objects except nil and false evaluate to a true value in conditional expressions.

And you may have a look at the control expressions.

How would I match nested if statements in regex? (using ruby)

It's basically the same as the regex for balanced parentheses that you linked to, but since the markers here are of multiple characters rather than single characters, you would need to use a negative lookahead pattern instead of simply a negated character class to ensure a matching character in the middle isn't part of the markers for the balanced construct:

{#if.*?}(?>(?!{(?:#if.*?|\/if)}).|\g<0>)*{\/if}

Demo: https://rubular.com/r/7BU2FStPEP34W4

Note that you should enable MULTILINE mode with the m option in order for . to match a newline character.

Ruby regular expression for conditional expression

You forgot the space after the comma.
Try /^constraint :(\w*), '(.*)'$/

Although to be more general, I'd go with this: /^constraint :([^,]+),\s*'(.*)'$/.

Conditional regex in Ruby

Your regex (?=.*(USD))(?(1)\d+|[a-zA-Z]) does not work because

  • (?=.*(USD)) - a positive lookahead, triggered at every location inside a string (if scan is used) that matches USD substring after any 0 or more chars other than line break chars as many as possible (it means, there will only be a match if there is USD somewhere on a line)
  • (?(1)\d+|[a-zA-Z]) - a conditional construct that matches 1+ digits if Group 1 matched (if there is USD), or, an ASCII letter will be tried. However, the second alternative pattern will never be tried, because you required USD to be present in the string for a match to occur.

Look at the USD 100 regex debugger, it shows exactly what happens when the (?=.*(USD))(?(1)\d+|[a-zA-Z]) regex tries to find a match:

  • Step 1 to 22: The lookahead pattern is tried first. The point here is that the match will fail immediately if the positive lookahead pattern does not find a match. In this case, USD is found at the start of the string (since the first time the pattern is tried, the regex index is at the string start position). The lookahead found a match.
  • Step 23-25: since a lookahead is a non-consuming pattern, the regex index is still at the string start position. The lookahead says "go-ahead", and the conditional construct is entered. (?(1) condition is met, Group 1, USD, was matched. So, the first, then, part is triggered. \d+ does not find any digits, since there is U letter at the start. The regex match fails at the string start position, but there are more positions in the string to test since there is no \A nor ^ anchor that would only let a match to occur if the match is found at the start of the string/line.
  • Step 26: The regex engine index is advanced one char to the right, now, it is right before the letter S.
  • Step 27-40: The regex engine wants to find 0+ chars and then USD immediately to the right of the current location, but fails (U is already "behind" the index).
  • Then, the execution is just the same as described above: the regex fails to match USD anywhere to the right of the current location and eventually fails.

If the USD is somewhere to the right of 100, then you'd get a match.

So, the lookahead does not set any search range, it simply allows matching the rest of the patterns (if its pattern matches) or not (if its pattern is not found).

You may use

.scan(/^USD.*?\K(\d+)|([a-zA-Z])/).flatten.compact

Pattern details

  • ^USD.*?\K(\d+) - either USD at the start of the string, then any 0 or more chars other than line break chars as few as possible, and then the text matched is dropped and 1+ digits are captured into Group 1
  • | - or
  • ([a-zA-Z]) - any ASCII letter captured into Group 2.

See Ruby demo:

p "USD 100".scan(/^USD.*?\K(\d+)|([a-zA-Z])/).flatten.compact
# => ["100"]
p "YEN 100".scan(/^USD.*?\K(\d+)|([a-zA-Z])/).flatten.compact
# => ["Y", "E", "N"]

Using code block in ruby's if statement

Use Enumerable#any?. See the reference docs: http://ruby-doc.org/core-2.0/Enumerable.html. This method (as well as Enumerable#all?) will return true or false.

Example:

msg_values.each do |msg|
if (SKIP_MSG_ARRAY.any? { |regular_exp| msg.match(regular_exp)})
# do something
else
# do something else
end
end


Related Topics



Leave a reply



Submit