Dave
Dave

Reputation: 19110

Matching strings that contain a letter with the first character not being a number

How do I write a regular expression that has at least one letter, but the first character must not be a number? I tried this

str = "a"
str =~ /^[^\d][[:space:]]*[a-z]*/i
# => 0 

str = "="
str =~ /^[^\d][[:space:]]*[a-z]*/i
# => 0 

The "=" is matched even though it contains no letters. I expect the"a"to match, and similarly a string like"3abcde"` should not match.

Upvotes: 2

Views: 157

Answers (2)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626747

The [a-z]* and [[:space:]]* patterns can match an empty string, so they do not really make any difference when validating is necessary. Also, = is not a digit, it is matched with [^\d] negated character class that is a consuming type of pattern. It means it requires a character other than a digit in the string.

You may rely on a lookahead that will restrict the start of string position:

/\A(?!\d).*[a-z]/im

Or even a bit faster and Unicode-friendly version:

/\A(?!\d)\P{L}*\p{L}/

See the regex demo

Details:

  • \A - start of a string
  • (?!\d) - the first char cannot be a digit
  • \P{L}* - 0 or more (*) chars other than letters
    or
  • .* - any 0+ chars, including line breaks if /m modifier is used)
  • \p{L} - a letter

The m modifier enables the . to match line break chars in a Ruby regex.

Use [a-z] when you need to restrict the letters to those in ASCII table only. Also, \p{L} may be replaced with [[:alpha:]] and \P{L} with [^[:alpha:]].

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110675

If two regular expressions were permitted you could write:

def pass_de_test?(str)
  str[0] !~ /\d/ && str =~ /[[:alpha]]/
end

pass_de_test?("*!\n?a>") #=> 4 (truthy)
pass_de_test?("3!\n?a>") #=> false

If you want true or false returned, change the operative line to:

str[0] !~ /\d/ && str =~ /[[:alpha]]/) ? true : false

or

!!(str[0] !~ /\d/ && str =~ /[[:alpha]]/)

Upvotes: 0

Related Questions