Search code examples
phpregexvalidationpreg-matchdelimited

Regex to match alphanumeric characters, underscore, periods and dash, allowing dot and dash only in the middle


Presently, I am using this:

if (preg_match ('/^[a-zA-Z0-9_]+([a-zA-Z0-9_]*[.-]?[a-zA-Z0-9_]*)*[a-zA-Z0-9_]+$/', $product) ) {
    return true;
} else { 
    return false
}

For example, I want to match:

  1. pro.duct-name_
  2. _pro.duct.name
  3. p.r.o.d_u_c_t.n-a-m-e
  4. product.-name
  5. ____pro.-_-.d___uct.nam._-e

But I don't want to match:

  1. pro..ductname
  2. .productname-
  3. -productname.
  4. -productname

Solution

  • The answer would be

    /^[a-zA-Z0-9_]+([-.][a-zA-Z0-9_]+)*$/
    

    if only you allowed strings containing .- and -. NOT to match. Why would you allow them to match, anyway? But if you really need these strings to match too, a possible solution is

    /^[a-zA-Z0-9_]+((\.(-\.)*-?|-(\.-)*\.?)[a-zA-Z0-9_]+)*$/
    

    The single . or - of the first regex is replaced by a sequence of alternating . and -, starting with either . or -, optionally followed by -. or .- pairs respectively, optionally followed by a - or . respectively, to allow for an even number of alternating chars. This complexity is probably an overshoot, but appears to be needed by current specifications. If a max of 2 alternating . and - is required, the regex becomes

    /^[a-zA-Z0-9_]+((\.-?|-\.?)[a-zA-Z0-9_]+)*$/
    

    Test here or here