Here are a three ways to do that.
#1 Use a regular expression with a capture group
r = /
\A # match beginning of string
[^[[:alnum:]]]* # match 0+ chars other than digits and lc letters
(\d+) # match 1+ digits in capture group 1
[^[[:alnum:]]]* # match 0+ chars other than digits and lc letters
\z # match end of string
/x # free-spacing regex definition mode
"$ ^*123@-"[r, 1] #=> '123'
"$ ^*123@-a?"[r, 1] #=> nil
"$9^*123@-"[r, 1] #=> nil
#2 Use a regular expression with \K
and a positive lookahead
r = /
\A # match beginning of string
[^[[:alnum:]]]* # match 0+ chars other than digits and lc letters
\K # discard all matched so far
\d+ # match 1+ digits
(?=[^[[:alnum:]]]*\z) # match 0+ chars other than digits and lc letters
# in a positive lookahead
/x # free-spacing mode
"$ ^*123@-"[r] #=> '123'
"$ ^*123@-a?"[r] #=> nil
"$9^*123@-"[r] #=> nil
Note that we cannot have a positive lookbehind in place of \K
as Ruby does not support variable-length lookbehinds.
#3 Use simpler regular expressions together with String
methods
def extract(str)
return nil if str =~ /[[:alpha:]]/
a = str.scan(/\d+/)
a.size == 1 ? a.first : nil
end
extract("$ ^*123@-") #=> '123'
extract("$ ^*123@-a?") #=> nil
extract("$9^*123@-") #=> nil