检查字符串中是否连续出现大写字母的正则表达式

87

我想知道以下情况下的正则表达式:

该字符串应只包含字母。它必须以大写字母开头,后跟小写字母。然后可以是小写字母或大写字母。

^[A-Z][a-z][A-Za-z]*$

但是该字符串也不能包含任何连续的大写字母。我如何将这个逻辑添加到正则表达式中?

也就是说,HttpHandler 正确,而 HTTPHandler 错误。

5个回答

187
每当使用[A-Z][a-z]时,就明确承诺仅处理来自1960年代的7位ASCII数据。如果这真的可以接受,那么很好。但如果不可接受,则Unicode字符属性可帮助您处理现代字符数据。
Unicode有三种情况,而不是两种。此外,您还有非大小写字母。一般情况下,字母由\pL属性指定,并且所有这些字母也属于五个子类别之一:
1. 大写字母,由\p{Lu}指定;例如:AÇDZÞΣSSὩΙST 2. 标题大小写字母,由\p{Lt}指定;例如:LjDzSsᾨSt(实际上SsSt分别是大写和小写字母,但它们确实是ß和ſt的标题大小写形式) 3. 小写字母,由\p{Ll}指定;例如:aαçdzςσþßᾡſt 4. 修饰字母,由\p{Lm}指定;例如:ʰʲᴴᴭʺˈˠᵠꜞ 5. 其他字母,由\p{Lo}指定;例如:ƻאᎯᚦ京
您可以对任何一个子类别取补集,但要小心,因为像\P{Lu}这样的表达式并不意味着不是大写字母的字母!它意味着任何不是大写字母的字符。
对于既是大写字母又是标题大小写字母的字母,请使用[\p{Lu}\p{Lt}]。因此,您可以在模式中使用:
 ^([\p{Lu}\p{Lt}]\p{Ll}+)+$

如果您不想仅限于第一个字母后的“大小写”字母,则可以选择以下方式:

 ^([\p{Lu}\p{Lt}][\p{Ll}\p{Lm}\p{Lo}]+)+$
如果你正在尝试匹配所谓的“驼峰式”标识符,那么实际规则取决于编程语言,但通常包括下划线字符和十进制数字(\p{Nd}),并且可能还包括一个字面上的美元符号和其他依赖于语言的字符。如果是这样,您可能希望将其中一种或两种提供的字符类别中的一些添加到其中之一。 例如,您可以希望在两个字符类别中都添加下划线,但仅将数字添加到第二个字符类别中,从而得到:
 ^([_\p{Lu}\p{Lt}][_\p{Nd}\p{Ll}\p{Lm}\p{Lo}]+)+$

然而,如果你在处理来自各种RFC和ISO标准的特定“单词”,通常会指定这些单词只包含ASCII。 如果是这样,你可以直接使用[A-Z]表达式,但如果实际上不存在该限制,则不应强加该限制。


完全同意限制。这里有更多关于此的信息:Regular-expressions.info - Daneo
3
如果你想在Python中使用're',你必须知道它不支持Unicode字符属性。http://pypi.python.org/pypi/regex可以支持。 - noisy
6
等一下,有人不使用 Perl 进行正则表达式匹配吗? - hd1
我一直没有弄清楚如何让你的示例工作。https://regex101.com/r/yYExY4/1 这些在regex101中的任何语言中都有效吗?我哪里理解有误了吗?谢谢。 - Ryan
1
@Ryan,这取决于你的要求 - 你的正则表达式只允许“大写字母A-Z和数字0-9”,且第一个字符不能是数字。-但是如果您的要求例如为“任何大写字母(任何语言)和任何数字(任何语言而不仅仅是0-9)-那么可以使用以下内容:[\ p {Lu} \ p {Lt}] [\ p {Lu} \ p {Nd}] +。 - Falco
显示剩余6条评论

51
请看tchrist的答案,特别是如果你开发网络应用或者更多的国际化内容。 Oren Trutner的答案并不完全正确(见输入样例 "RightHerE" 无法被匹配却应该被匹配)。
以下是正确的解决方案:
(?!^.*[A-Z]{2,}.*$)^[A-Za-z]*$

解释:

(?!^.*[A-Z]{2,}.*$)  // don't match the whole expression if there are two or more consecutive uppercase letters
^[A-Za-z]*$          // match uppercase and lowercase letters

/edit

这个问题的关键在于使用负向先行断言。详情请见:先行和后行零宽度断言


? ! . 等符号代表什么意思? - kiki
2
这是一个负向先行断言(negative lookahead)-详细解释请参见我发布的链接。基本上,它的意思是如果在负向先行断言之间的正则表达式匹配,则整个表达式不匹配。因此,例如,您可以说:^[0-9]$(匹配从0到9的一个数字),并且您可以说(?!^3$)^[0-9]$(匹配从0到9的一个数字,但不包括3)。 - Stephan Schinkel

11
^([A-Z][a-z]+)+$

这个正则表达式匹配一个大写字母后跟一个或多个小写字母的序列。连续的大写字母不会匹配,因为每次只允许一个,而且它必须后跟一个小写字母。


请原谅我的无知。看,这是我现在的正则表达式:(^[A-Z][a-z][A-Za-z]$)|(^I[A-Z][a-z][A-Za-z]$)。我需要添加逻辑来检查大写字母不会连续出现在 [A-Za-z] 部分中。你有什么建议?+ 究竟意味着什么? - kiki
这不会匹配有效的 TestX,因为您不会匹配最后一个大写字母。 - Falco

8
除了tchrist的优秀帖子关于Unicode之外,我认为您不需要使用负向先行断言的复杂解决方案... 您的定义要求大写字母后跟至少一个组(小写字母后可选大写字母):
^
[A-Z]    // Start with an uppercase Letter
(        // A Group of:
  [a-z]  // mandatory lowercase letter
  [A-Z]? // an optional Uppercase Letter at the end
         // or in between lowercase letters
)+       // This group at least one time
$

我认为它只是更加紧凑和易于阅读...


-20
如果您想在MySQL中获取所有至少有一个大写字母的员工姓名,请应用以下查询:
SELECT * FROM registration WHERE `name` REGEXP BINARY '[A-Z]';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接