You are asking that the string (s
) satisfies this condition (note: let c∈s
mean c∈{x|x is a character in s}
. Also, []
represent regex character classes):
(∀c∈s (c∈[0-9A-Za-z ])) ∧ (∃c∈s ∋ c∈[0-9A-Za-z])
Consider the negation:
¬((∀c∈s c∈[0-9A-Za-z ]) ∧ (∃c∈s ∋ c∈[0-9A-Za-z]))
⇔
(∃c∈s ∋ c∉[0-9A-Za-z ]) ∨ (∀c∈s c∉[0-9A-Za-z])
⇔
(∃c∈s ∋ c∈[^0-9A-Za-z ]) ∨ (∀c∈s c∈[^0-9A-Za-z])
So now we want to construct a regex that either contains a non-alphanumeric and non-space character or consists only of non-alphanumeric characters.
The first is easy: [^0-9A-Za-z ]
.
The second is like unto it: ^[^0-9A-Za-z]*$
Combine them together to get: [^0-9A-Za-z ]|^[^0-9A-Za-z]*$
Now we need to negate this regex. Obviously, we could just do (?![^0-9A-Za-z ]|^[^0-9A-Za-z]*$)
. Or we could manually negate the regex:
[^0-9A-Za-z ]
becomes ^[0-9A-Za-z ]*$
^[^0-9A-Za-z]*$
becomes [0-9A-Za-z]
. (note: we could easily have arrived here from the beginning)
But now we need to combine them with AND, not OR:
Since [0-9A-Za-z]
is a subset of [0-9A-Za-z ]
, we can simply do this:
^[0-9A-Za-z ]*[0-9A-Za-z][0-9A-Za-z ]*$
Note that we can simplify it down to:
^[0-9A-Za-z ]*[0-9A-Za-z][ ]*$
This just requires that the character that matches [0-9A-Za-z]
is the last character that could do so. We could also do
^[ ]*[0-9A-Za-z][0-9A-Za-z ]*$
Which would require that the character that matches [0-9A-Za-z]
is the first character that could do so.
So now we're done. We can either use one of those or (?![^0-9A-Za-z ]|^[^0-9A-Za-z]*$)
.
Note: String#match
acts as if the regex is ^ + regex + $
(where +
is concatenation). This can throw a few things off.