Learning to Use Regular Expressions by Example

ote that you must always specify the first number of a range (i.e,"{0,2}", not "{,2}"). Also, as you might have noticed, the symbols '*', '+', and '?' have the same effect as using the bounds "{0,}", "{1,}", and "{0,1}", respectively.

Now, to quantify a sequence of characters, put them inside parentheses:

  • "a(bc)*": matches a string that has an a
    followed by zero or more copies of the sequence "bc";

  • "a(bc){1,5}": one through five copies of "bc."

lso the '|' symbol, which works as an OR operator:

  • "hi|hello": matches a string that has either
    "hi" or "hello" in it;

  • "(b|cd)ef": a string that has either "bef" or
    "cdef";

  • "(a|b)*c": a string that has a sequence of alternating a's
    and b's ending in a c;

) stands for any single character:

  • "a.[0-9]": matches a string that has an a
    followed by one character and a digit;

  • "^.{3}$": a string with exactly 3 characters.

t expressions specify which characters are allowed in a single
position of a string:

  • "[ab]": matches a string that has either an a or
    a b (that's the same as "a|b");

  • "[a-d]": a string that has lowercase letters 'a'
    through 'd' (that's equal to "a|b|c|d" and even "[abcd]");

  • "^[a-zA-Z]": a string that starts with a letter;
  • "[0-9]%": a string that has a single digit before a
    percent sign;

  • ",[a-zA-Z0-9]$": a string that ends in a comma followed
    by an alphanumeric character.

haracters you DON'T want -- just use a '^' as the
first symbol in a bracket expression (i.e., "%[^a-zA-Z]%"
matches a string with a character that is not a letter between two percent
signs).

In order to be taken literally, you must escape the characters
"^.[$()|*+?{" with a backslash (''), as they have special meaning.
On top of that, you must escape the backslash character itself in PHP3 strings,
so, for instance, the regular expression "($|Â¥)[0-9]+"
would have the function call: ereg("($|Â¥)[0-9]+", $str)
(what string does that validate?)

Just don't forget that bracket expressions are an exception to that
rule--inside them, all special characters, including the backslash (''), lose
their special powers (i.e., "[*+?{}.]" matches exactly any
of the characters inside the brackets). And, as the regex man pages tell us:
"To include a literal ']' in the list, make it the first character
(following a possible '^'). To include a literal '-', make it the first or last
character, or the second endpoint of a range."

For completeness, I should mention that there are also collating
sequences
, character classes, and equivalence classes. I
won't be getting into details on those, as they won't be necessary for what
we'll need further down this article. You should refer to the regex man pages
for more information.

lidating Money Strings

Ok, we can now use what we've learned to work on something useful: a regular
expression to check user input of an amount of money. A quantity of money can be
written in four ways we can consider acceptable: "10000.00" and
"10,000.00", and, without the cents, "10000" and
"10,000". Let's begin with:

^[1-9][0-9]*$

That validates any number that doesn't start with a 0. But that also means
the string "0" doesn't pass the test. Here's a solution:

^(0|[1-9][0-9]*)$

"Just a zero OR some number that doesn't start with a zero." We may
also allow a minus sign to be placed before the number:

^(0|-?[1-9][0-9]*)$

That means: "a zero OR a possible minus sign and a number that doesn't
start with a zero." Ok, let's not be so strict and let the user start the
number with a zero. Let's also drop the minus sign, as we won't be needing it
for the money string. What we could do is specify an optional decimal fraction
part in the number:

^[0-9]+(.[0-9]+)?$

It's implicit in the highlited construct that a period always comes with at
least one digit, as a whole set. So, for instance, "10." is not
validated, whereas "10" and "10.2" are.

^[0-9]+(.[0-9]{2})?$

We specified that there must be exactly two decimal places. If you think
that's too harsh, you can do the following:

^[0-9]+(.[0-9]{1,2})?$

That allows the user to write just one number after the period. Now, as for
the commas separating the thousands, we can put in:

^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$

"A set of 1 to 3 digits followed by zero or more sets of a comma and
three digits." Easy enough, isn't it? But let's make the commas optional:

^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$

That's it. Don't forget that the '+' can be substituted by a '*' if you want
empty strings to be accepted also (why?). And don't forget to escape the
backslash for the function call (common mistake here). Now, once the string is
validated, we strip off any commas with str_replace(",",
"", $money)
and typecast it to double so we can
make math with it.