I need this lately, so I created one that perfectly matches the syntax of the LDAPv3 syntax in RFC-2253 .
Attribute type
An attribute type can be expressed in two ways. Alphanumeric string starting with alpha using:
[A-Za-z][\w-]*
Or it could be an OID verified with:
\d+(?:\.\d+)*
Thus, the typeType attribute checks for use:
[A-Za-z][\w-]*|\d+(?:\.\d+)*
Attribute value
An attribute value can be expressed in three ways. A hexadecimal string, which is a sequence of hexadecimal pairs with leading # . The hex string is checked using:
#(?:[\dA-Fa-f]{2})+
Or an escaped string; each non-special character is expressed "as is" (checked using [^,=\+<>#;\\"] ). Special characters can be expressed using the host \ (checks to use \\[,=\+<>#;\\"] ). Finally, any character can be expressed as a hexadecimal pair with a leading \ (checks for the use of \\[\dA-Fa-f]{2} ). An escaped string is checked with:
(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*
Or a quoted string; the value begins and ends with " , and may contain any character that is not reset except for \ and " . In addition, you can use any of the methods from the above line. The quote checks using:
"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*"
All together, the value attribute checks for use:
#(?:[\dA-Fa-f]{2})+|(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*|"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*"
Name component
Name component in BNF:
name-component = attributeTypeAndValue *("+" attributeTypeAndValue) attributeTypeAndValue = attributeType "=" attributeValue
RegEx has:
(?#attributeType)=(?#attributeValue)(?:\+(?#attributeType)=(?#attributeValue))*
Replacing the placeholders (?#attributeType) and (?#attributeValue) the above values ββgives us:
(?:[A-Za-z][\w-]*|\d+(?:\.\d+)*)=(?:#(?:[\dA-Fa-f]{2})+|(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*|"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*")(?:\+(?:[A-Za-z][\w-]*|\d+(?:\.\d+)*)=(?:#(?:[\dA-Fa-f]{2})+|(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*|"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*"))*
Which checks one component of the name.
Distinguished name
Finally, BNF for the distinguished name:
name-component *("," name-component)
RegEx has:
(?#name-component)(?:,(?#name-component))*
Replacing the placeholder (? # Name-component) with the value above gives us:
^(?:[A-Za-z][\w-]*|\d+(?:\.\d+)*)=(?:#(?:[\dA-Fa-f]{2})+|(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*|"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*")(?:\+(?:[A-Za-z][\w-]*|\d+(?:\.\d+)*)=(?:#(?:[\dA-Fa-f]{2})+|(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*|"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*"))*(?:,(?:[A-Za-z][\w-]*|\d+(?:\.\d+)*)=(?:#(?:[\dA-Fa-f]{2})+|(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*|"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*")(?:\+(?:[A-Za-z][\w-]*|\d+(?:\.\d+)*)=(?:#(?:[\dA-Fa-f]{2})+|(?:[^,=\+<>#;\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*|"(?:[^\\"]|\\[,=\+<>#;\\"]|\\[\dA-Fa-f]{2})*"))*)*$
Test it here