问题中的规范不是很清楚,所以我假设字符串只能包含 ASCII 字母和数字,并使用连字符、下划线和空格作为内部分隔符。问题的实质是确保第一个和最后一个字符不是分隔符,并且一行中永远不会有多个分隔符(无论如何,这部分似乎很清楚)。这是最简单的方法:
/^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/
匹配一个或多个字母数字字符后,if有一个分隔符must后跟一个或多个字母数字;根据需要重复。
让我们看看其他一些答案中的正则表达式。
/^[[:alnum:]]+(?:[-_ ]?[[:alnum:]]+)*$/
这实际上是相同的(假设您的正则表达式风格支持 POSIX 字符类表示法),但为什么要使分隔符可选呢?您首先出现在正则表达式的该部分的唯一原因是是否存在分隔符或其他无效字符。
/^[a-zA-Z0-9]+([_\s\-]?[a-zA-Z0-9])*$/
另一方面,这只适用于because分隔符是可选的。在第一个分隔符之后,它一次只能匹配一个字母数字。为了匹配更多,它必须不断重复整个组:零分隔符后跟一个字母数字,一遍又一遍。如果第二个[a-zA-Z0-9]
后面跟着一个加号,它可以通过更直接的路线找到匹配项。
/^[a-zA-Z0-9][a-zA-Z0-9_\s\-]*[a-zA-Z0-9](?<![_\s\-]{2,}.*)$/
这使用了无限制的后向查找,这是一个非常罕见的功能,但是您可以使用前向查找来达到相同的效果:
/^(?!.*[_\s-]{2,})[a-zA-Z0-9][a-zA-Z0-9_\s\-]*[a-zA-Z0-9]$/
这实际上对两个连续的分隔符执行单独的搜索,如果找到一个则匹配失败。然后主体只需要确保所有字符都是字母数字或分隔符,第一个和最后一个是字母数字。由于这两个字符是必需的,因此名称的长度必须至少为两个字符。
/^[a-zA-Z0-9]+([a-zA-Z0-9](_|-| )[a-zA-Z0-9])*[a-zA-Z0-9]+$/
这是您自己的正则表达式,它要求字符串以两个字母数字字符开头和结尾,如果字符串中有两个分隔符,则它们之间必须恰好有两个字母数字。所以ab
, ab-cd
and ab-cd-ef
会匹配,但是a
, a-b
and a-b-c
won't.
此外,正如一些评论者所指出的,(_|-| )
在你的正则表达式中应该是[-_ ]
。那部分不是不正确,但是如果您可以在交替和字符类之间进行选择,那么您应该始终选择字符类:它们更高效且更具可读性。
再说一次,我并不担心“字母数字”是否应该包含非 ASCII 字符,或者“空格”的确切含义,而只是担心如何使用正则表达式强制执行非连续内部分隔符的策略。