6
votes

I haven't been able to find this one and what I'm trying isn't quite working out for me.

I want to match only domains that:

  • don't contain a protocol (http, https, ftp)
  • optionally include a subdomain
  • don't start with a hyphen but can contain a hyphen

Example domains that would match:

  • domain.com
  • example.domain.com
  • example.domain-hyphen.com
  • www.domain.com
  • example.museum

Example domains that would not match:

  • http://example.com
  • subdomain.-example.com
  • example.com/parameter
  • example.com?anything
  • www.subdomain.domain.com

What I've currently got:

/^(?!:\/\/)(^[a-zA-Z0-9])?.[a-zA-Z0-9-]+\.[a-zA-Z]{2,6}?$/i

It's not matching protocols, allowing hyphen inside the domain, not allowing trailing characters after the TLD, and is allowing a subdomain (but only 1 character).

I still need to allow subdomains of any length, not allow www.subdomain.domain.com and not allow a leading hyphen.

4
How do you define "domain" then? Every word with at least one dot in it?Bergi
Not sure I understand. domain precedes the TLD and can only contain letters, numbers and a hyphen.Jared Eitnier
Well, that was my (failed) attempt at allowing subdomains. Basically that's where I got stuck and the last thing I added to this regex.Jared Eitnier

4 Answers

15
votes

Try

/^(?!:\/\/)([a-zA-Z0-9]+\.)?[a-zA-Z0-9][a-zA-Z0-9-]+\.[a-zA-Z]{2,6}?$/i
4
votes

Let's analyse your regex:

^(?!:\/\/)

This is pretty useless. While it indicates the intention of the regex, it's unnecessary since the following characters are not allowed to contain slashes anyway.

(^[a-zA-Z0-9])?.

I think you wanted this to be ^([a-zA-Z0-9]+\.)?. Your dot is not escaped, and would be preceded by only one optional character at the string beginning.

[a-zA-Z0-9-]+

If you want this not to begin with a hyphen, you either could use a negative lookahead or better just [a-zA-Z0-9][a-zA-Z0-9-]*.

\.[a-zA-Z]{2,6}?

Not sure what the question mark does here. There's no backtracking anyway?

/i

This renders the explicit [a-zA-Z] useless, one would be enough. Or omit the i flag.

All these things together, we will end up with

/^([a-z0-9]+\.)?[a-z0-9][a-z0-9-]*\.[a-z]{2,6}$/i
2
votes

Try this:

^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$

Demo

0
votes

The RegEx I came up with while doing the Hostname/FQDN validation in Javascript:

FQDN:

^(?!:\/\/)(?!.{256,})(([a-z0-9][a-z0-9_-]*?\.)+?[a-z]{2,6}?)$/i

Hostname or FQDN

^(?!:\/\/)(?!.{256,})(([a-z0-9][a-z0-9_-]*?)|([a-z0-9][a-z0-9_-]*?\.)+?[a-z]{2,6}?)$/i

Both expressions use lookahead to check the total string length, which can be up to 255 characters. They also do a lazy check .{x,y}?.

Note that it is using case insensitive match /i.