A revised regex based on comments here and my own reading of RFCs 1035 & 1123:
Ruby: \A(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\z
(tests below)
Python: ^(?!-)[a-zA-Z0-9-]{1,63}(?<!-)$
(not tested by me)
Javascript: pattern = /^(?!-)[a-zA-Z0-9-]{1,63}$/g;
(based on Tom Lime's answer, not tested by me)
Tests:
tests = [
['01010', true],
['abc', true],
['A0c', true],
['A0c-', false],
['-A0c', false],
['A-0c', true],
['o123456701234567012345670123456701234567012345670123456701234567', false],
['o12345670123456701234567012345670123456701234567012345670123456', true],
['', false],
['a', true],
['0--0', true],
["A0c\nA0c", false]
]
regex = /\A(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\z/
tests.each do |label, expected|
is_match = !!(regex =~ label)
puts is_match == expected
end
Notes:
- Thanks to Mark Byers for the original code fragment
- solidsnack points out that RFC 1123 allows all-numeric labels (https://www.rfc-editor.org/rfc/rfc1123#page-13)
- RFC 1035 does not allow zero-length labels (https://www.rfc-editor.org/rfc/rfc1035):
<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
- I've added a test specifically for Ruby that ensures a new line is not embedded in the label. This is thanks to notes by ssorallen.
- This code is available here: https://github.com/Xenapto/domain-label-validation - I'm happy to accept pull requests if you want to update it.
<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
which means that zero-length labels are not allowed – Ottinger