Does anyone know how to write a regexp that only allows a-zA-Z0-9.- (letters, numbers, dots, and dash) BUT that never starts or ends with a dot or dash ?
I tried this one :
/^[^.-][a-zA-Z0-9.-]+[^.-]$/
... but if I write something like "john@", it works, and I don't want to because @ is not allowed.
The domain name should be a-z or A-Z or 0-9 and hyphen (-). The domain name should be between 1 and 63 characters long. The domain name should not start or end with a hyphen(-) (e.g. -geeksforgeeks.org or geeksforgeeks.org-). The last TLD (Top level domain) must be at least two characters and a maximum of 6 characters.
A subdomain is a prefix added to a domain name to separate a section of your website. Site owners primarily use subdomains to manage extensive sections that require their own content hierarchy, such as online stores, blogs or support platforms. Subdomains function as a separate website from its domain.
According to the pertinent internet recommendations (RFC3986 section 2.2, which in turn refers to: RFC1034 section 3.5 and RFC1123 section 2.1), a subdomain (which is a part of a DNS domain host name), must meet several requirements:
[A-Za-z]
or digits [0-9]
).Here is an expression fragment for a subdomain part which meets these requirements:
[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?
Note that this expression fragment should not be used alone - it requires the incorporation of boundary conditions in a larger context, as demonstrated in the following expression for a DNS host name...
A named host, (not an IP address), must meet additional requirements:
With this is mind, here a commented regex (in PHP syntax), which will pseudo-validate a DNS host name: (Note that this incorporates a modified version of the above expression for a subdomain and adds comments to this as well).
Update 2016-08-20: Since this answer was originally posted back in 2011, the number of top-level domains has exploded. As of August 2016 there are now more than 1400. The original regex to this answer incorporated all of these but this is no loger practical. The new regex below incorporates a different expression for the top-level domain. The algorithm comes from: Top Level Domain Name Specification draft-liman-tld-names-06.
$DNS_named_host = '%(?#!php/i DNS_named_host Rev:20160820_0800)
# Match DNS named host domain having one or more subdomains.
# See: http://stackoverflow.com/a/7933253/433790
^ # Anchor to start of string.
(?!.{256}) # Whole domain must be 255 or less.
(?: # One or more sub-domains.
[a-z0-9] # Subdomain begins with alpha-num.
(?: # Optionally more than one char.
[a-z0-9-]{0,61} # Middle part may have dashes.
[a-z0-9] # Starts and ends with alpha-num.
)? # Subdomain length from 1 to 63.
\. # Required dot separates subdomains.
)+ # End one or more sub-domains.
(?: # Top level domain (length from 1 to 63).
[a-z]{1,63} # Either traditional-tld-label = 1*63(ALPHA).
| xn--[a-z0-9]{1,59} # Or an idn-label = Restricted-A-Label.
) # End top level domain.
$ # Anchor to end of string.
%xi'; // End $DNS_named_host.
Note that this expression is not perfect. It requires one or more subdomains, but technically, a host can consist of a TLD having no subdomain (but this is rare).
Update 2014-08-12: Added simplified expression for subdomain which does not require alternation.
Update 2016-08-20: Modified DNS host name regex to (more generally) match the new vast number of valid top level domains. Also, trimmed out unnecessary material from answer.
You want the first and last characters limited to alphanumeric. What you have now allows the first and last characters to be anything other than dot and dash. This fits the description:
/^[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9]$/
Here is DOMAIN + SUBDOMAIN solution that may help to someone else:
/^([a-zA-Z0-9]([-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?\.)?([a-zA-Z0-9]{1,2}([-a-zA-Z0-9]{0,252}[a-zA-Z0-9])?)\.([a-zA-Z]{2,63})$/
which passes following chai tests:
const expect = require('chai').expect;
function testDomainValidNamesRegExp(val) {
let names = /^([a-zA-Z0-9]([-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?\.)?([a-zA-Z0-9]([-a-zA-Z0-9]{0,252}[a-zA-Z0-9])?)\.([a-zA-Z]{2,63})$/;
return names.test(val);
}
let validDomainNames = [
"example.com",
"try.direct",
"my-example.com",
"subdomain.example.com",
"example.com",
"example23.com",
"regexp-1222.org",
"read-book.net",
"org.host.org",
"org.host.org",
"velmart.shop-products.md",
"ip2email.terronosp-222.lb",
"stack.com",
"sta-ck.com",
"sta---ck.com",
"9sta--ck.com",
"sta--ck9.com",
"stack99.com",
"99stack.com",
"sta99ck.com",
"sub.do.com",
"ss.sss-ss.ss",
"s.sss-ss.ss",
"s.s-s.ss",
"test.t.te"
];
let invalidDomainNames = [
"example2.com222",
"@example.ru:?",
"example22:89",
"@[email protected]@22-",
"example.net?1222",
"example.com:8080:",
".example.com:8080:",
"---test.com",
"$dollars$.gb",
"sell-.me",
"[email protected]",
"mem-.wer().or%:222",
"pop().addjocker.lon",
"regular-l=.heroes?",
" ecmas cript-8.org ",
"example.com::%",
"example:8080",
"example",
"examaple.com:*",
"-test.test.com",
"-test.com",
"dd-.test.com",
"dfgdfg.dfgdf33.e",
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd-.test.com",
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd.testttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt.com",
"d-.test.com"
];
describe("Test Domain Valid Names RegExp", () => {
validDomainNames.forEach((val) => {
it(`Text: ${val}`, () => {
expect(testDomainValidNamesRegExp(val)).to.be.true;
});
});
});
describe("Test Domain Invalid Names RegExp", () => {
invalidDomainNames.forEach((val) => {
it(`Text: ${val}`, () => {
expect(testDomainValidNamesRegExp(val)).to.be.false;
});
});
});
More tests are very welcome !
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With