I'd suggest to check for the length outside of the regular expression, otherwise the expression might get too complicated.
Here's an example snippet in JavaScript:
if (str.length < 8 || str.length > 20)
return false;
if (str.match(/(^\s|\s$|\s\s|[^A-Za-z.\s])/))
return false;
The regular expression checks for a match of any of the forbidden patterns:
^\s
a whitespace at the beginning
\s$
a whitespace at the end
\s\s
two consecutive whitespace characters
[^A-Za-z.\s]
a character that is not a letter, period or whitespace
If you will allow only spaces (ASCII 32), not tabs or other whitespace characters, you can replace all \s
by the literal space character.
Another solution would be a combination of a “positive” expression to check for the permitted characters and length and a “negative” one to rule out the rejected patterns:
return str.match(/[A-Za-z. ]){8,20}/) && !str.match(/(^ | $| )/);
Update: If you need to put everything into a single expression, I'm afraid you have to leave out the check for consecutive spaces, because this restriction makes the language context-sensitive, hence it cannot be checked by a regular expression. What you can do is to check for a string that begins with a letter, followed by 6 to 18 letters, dots or spaces and ends with a letter:
[A-Z][A-Z. ]{6,18}[A-Z]