How to Make Part of a Regular Expression Optional in Ruby

How do I make part of a regular expression optional in Ruby?

Sure. Put it in parentheses, put a question mark after it. Include one of the spaces (since otherwise you'll be trying to match two spaces if the "at" is missing.) (at )? (or as someone else suggested, (?:at )? to avoid it being captured).

Making part of the regex optional

I changed you Regex just slightly, and I am able to match both strings. The regex I have is:

/On.* \d{1,2}\/\d{1,2}\/\d{1,4}(?:, at)? \d{1,2}:\d{1,2} (?:AM|PM),.*wrote:/ 

Comparing the results of the two:

irb(main):023:0> s1 = "On 25/03/2011, at 2:19 AM, XXXXX XXXXXXXX wrote:"
=> "On 25/03/2011, at 2:19 AM, XXXXX XXXXXXXX wrote:"
irb(main):024:0> s2 = "On 3/14/11 2:55 PM, XXXXX XXXXXX wrote:"
=> "On 3/14/11 2:55 PM, XXXXX XXXXXX wrote:"
#Your previous Regex
irb(main):025:0> m = /On.* \d{1,2}\/\d{1,2}\/\d{1,4}(, at)? \d{1,2}:\d{1,2}(?:AM|PM),.*wrote:/
=> /On.* \d{1,2}\/\d{1,2}\/\d{1,4}(?:, at) \d{1,2}:\d{1,2} (?:AM|PM),.*wrote:/
irb(main):026:0> s1.match(m)
=> #<MatchData "On 25/03/2011, at 2:19 AM, XXXXX XXXXXXXX wrote">
irb(main):027:0> s2.match(m)
=> nil

#The updated Regex
irb(main):028:0> m = /On.* \d{1,2}\/\d{1,2}\/\d{1,4}(?:, at)? \d{1,2}:\d{1,2} (?:AM|PM),.*wrote/
=> /On.* \d{1,2}\/\d{1,2}\/\d{1,4}(?:, at)? \d{1,2}:\d{1,2} (?:AM|PM),.*wrote/
irb(main):029:0> s1.match(m)
=> #<MatchData "On 25/03/2011, at 2:19 AM, XXXXX XXXXXXXX wrote">
irb(main):030:0> s2.match(m)
=> #<MatchData "On 3/14/11 2:55 PM, XXXXX XXXXXX wrote">

(Ruby) regex optional matches

Try ^(.*?)?(\.?lvh\.me)?(\:\d+)?$

I added:

  • a ? to the first group making the * non-greedy
  • ^,$ to anchor it to the start and end.
  • a ? to the \. before lvh because you want to match not

How can I make part of regex optional?

To make the .+ optional, you could do:


(?:..) is called a non-capturing group. It only does the matching operation and it won't capture anything. Adding ? after the non-capturing group makes the whole non-capturing group optional.

Alternatively, you could do:


.* would match any character zero or more times greedily. Adding ? after the * forces the regex engine to do a shortest possible match.

Regex to match a String with optional Conditions

This seems to catch the date info. I purposely captured in groups, making it easier to build a real date:

regex = /^On (\w+ \d+, \d+), \w+ (\S+) (\w*)\s*,/

'On Feb 23, 2011, at 10:22 , James Bond wrote:',
'On Feb 23, 2011, at 10:22 AM , James Bond wrote:'
].each do |ary|
ary =~ regex
puts "#{$1} #{$2} #{$3}"
# >> Feb 23, 2011 10:22
# >> Feb 23, 2011 10:22 AM

I purposed didn't try to match on the months. Your sample strings look like quote headers from email messages. Those are very standard and generated by software, so you should see a lot of consistency in the format, allowing some simplification in the regex. If you can't trust those, then go with the matches on month name abbreviations to help ignore false-positive matches. The same things apply for the day, year, and time values.

The important thing in the regex is how to deal with the AM/PM when it's missing.

Optional named group in Ruby RegExp

You need to add (?:\s+(?<http_x_forwarded_for>\S+))? optional non-capturing group after the last field pattern. That means the named capturing group should be inside an optional non-capturing one, and \s+ should be placed before it to take into account any 1+ whitespace chars before the field.


^(?<remote>\S*) (?<host>\S*) (?<user>\S*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^"]*?)(?:\s+\S*)?)?" (?<code>\S*) (?<size>\S*)(?: "(?<referer>[^"]*)" "(?<agent>[^"]*)"(?:\s+(?<http_x_forwarded_for>\S+))?)?$

See the regex demo.

Note I replaced [^ ] with \S that is more natural to match chars other than whitespace chars with regex.

Ruby Regex with Optional Match

Do not use a ? quantifier on the claiming price capturing group (i.e. keep it obligatory, matching exactly once) and wrap it together with the .*? that is before it within an optional non-capturing group:

/(Thoroughbred)(?:.*?(?<claiming_price>Claiming Price:.*?\n))?.*Track Record:/m
^^ ^^

See the Rubular demo

Now, it will work like this:

  • (Thoroughbred) - Thoroughbred substring
  • (?:.*?(?<claiming_price>Claiming Price:.*?\n))? - one or zero (?) occurrences of:

    • .*? - any 0+ chars as few as possible up to the first occurrence of the subsequent subpatterns
    • (?<claiming_price>Claiming Price:.*?\n) - claiming_price group capturing

      • Claiming Price: - Claiming Price: substring
      • .*?\n - any 0+ chars as few as possible, up to the first newline
  • .* - any 0+ chars as many as possible up to the last occurrence of
  • Track Record: - Track Record: string.

Why didn't it work with the first regex of yours?

The (Thoroughbred) matched Thoroughbred. Then .*? pattern, being lazily quantified, was skipped at first, and (?<claiming_price>Claiming Price:.*?\n)? was tried. Since Claiming Price: is missing right after Thoroughbred, the pattern, quantified with ?, matched an empty string (since ? quantifier can match 1 or 0 of such pattern sequences). Then, .*Track Record: grabbed the rest of the match (any 0+ chars up to the last occurrence of Track Record:).

Optional whitespace in regexp

Make the inbetween \s as optional.

def suffixes(t)
(t.scan /\((\w+),\s?(\w+)\)/).flatten

? after the \s would turn the space to optional (0 or 1).

Related Topics

Leave a reply