将这两个正则表达式合二为一

我在C#中有以下内容:

public static bool IsAlphaAndNumeric(string s) { return Regex.IsMatch(s, @"[a-zA-Z]+") && Regex.IsMatch(s, @"\d+"); } 

我想检查参数s包含至少一个字母字符一个数字,我写了上面的方法来执行此操作。

但是有没有办法将两个正则表达式( "[a-zA-Z]+""\d+" )组合成一个?

 @"^(?=.*[a-zA-Z])(?=.*\d)" ^ # From the begining of the string (?=.*[a-zA-Z]) # look forward for any number of chars followed by a letter, don't advance pointer (?=.*\d) # look forward for any number of chars followed by a digit) 

使用两个正向前瞻以确保它找到一个字母,并在成功之前找到一个数字。 你添加^只是尝试从字符串的开头向前看一次。 否则,regexp引擎会尝试匹配字符串中的每个点。

对于带有LINQ的C#:

 return s.Any(Char.IsDigit) && s.Any(Char.IsLetter); 

你可以使用[a-zA-Z].*[0-9]|[0-9].*[a-zA-Z] ,但我只推荐你使用的系统只接受一个正则表达式。 我无法想象这会比没有交替的两个简单模式更有效。

它不完全是你想要的,但让我说我有更多的时间。 以下应该比正则表达式更快。

  static bool IsAlphaAndNumeric(string str) { bool hasDigits = false; bool hasLetters=false; foreach (char c in str) { bool isDigit = char.IsDigit(c); bool isLetter = char.IsLetter(c); if (!(isDigit | isLetter)) return false; hasDigits |= isDigit; hasLetters |= isLetter; } return hasDigits && hasLetters; } 

为什么它快速检查出来。 以下是测试字符串生成器。 它生成1/3的设置完全正确的字符串和2/3的广告不正确。 在2/3 1/2中所有的alphs和另一半都是数字。

  static IEnumerable GenerateTest(int minChars, int maxChars, int setSize) { string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; string numbers = "0123456789"; Random rnd = new Random(); int maxStrLength = maxChars-minChars; float probablityOfLetter = 0.0f; float probablityInc = 1.0f / setSize; for (int i = 0; i < setSize; i++) { probablityOfLetter = probablityOfLetter + probablityInc; int length = minChars + rnd.Next() % maxStrLength; char[] str = new char[length]; for (int w = 0; w < length; w++) { if (probablityOfLetter < rnd.NextDouble()) str[w] = letters[rnd.Next() % letters.Length]; else str[w] = numbers[rnd.Next() % numbers.Length]; } yield return new string(str); } } 

以下是darin两种解决方案。 一个已编译,另一个是非编译版本。

 class DarinDimitrovSolution { const string regExpression = @"^(?=.*[az])(?=.*[AZ])(?=.*\d).+$"; private static readonly Regex _regex = new Regex( regExpression, RegexOptions.Compiled); public static bool IsAlphaAndNumeric_1(string s) { return _regex.IsMatch(s); } public static bool IsAlphaAndNumeric_0(string s) { return Regex.IsMatch(s, regExpression); } 

以下是测试循环的主要内容

  static void Main(string[] args) { int minChars = 3; int maxChars = 13; int testSetSize = 5000; DateTime start = DateTime.Now; foreach (string testStr in GenerateTest(minChars, maxChars, testSetSize)) { IsAlphaNumeric(testStr); } Console.WriteLine("My solution : {0}", (DateTime.Now - start).ToString()); start = DateTime.Now; foreach (string testStr in GenerateTest(minChars, maxChars, testSetSize)) { DarinDimitrovSolution.IsAlphaAndNumeric_0(testStr); } Console.WriteLine("DarinDimitrov 1 : {0}", (DateTime.Now - start).ToString()); start = DateTime.Now; foreach (string testStr in GenerateTest(minChars, maxChars, testSetSize)) { DarinDimitrovSolution.IsAlphaAndNumeric_1(testStr); } Console.WriteLine("DarinDimitrov(compiled) 2 : {0}", (DateTime.Now - start).ToString()); Console.ReadKey(); } 

以下是结果

 My solution : 00:00:00.0170017 (Gold) DarinDimitrov 1 : 00:00:00.0320032 (Silver medal) DarinDimitrov(compiled) 2 : 00:00:00.0440044 (Gold) 

所以第一个解决方案是最好的。 还有一些会导致发布模式和遵循规范

  int minChars = 20; int maxChars = 50; int testSetSize = 100000; My solution : 00:00:00.4060406 DarinDimitrov 1 : 00:00:00.7400740 DarinDimitrov(compiled) 2 : 00:00:00.3410341 (now that very fast) 

我再次使用RegexOptions.IgnoreCase标志检查。 其余的param与上面相同

 My solution : 00:00:00.4290429 (almost same as before) DarinDimitrov 1 : 00:00:00.9700970 (it have slowed down ) DarinDimitrov(compiled) 2 : 00:00:00.8440844 ( this as well still fast but look at .3 in last result) 

在gnarf提到我的算法存在问题后,它检查字符串是否只包含字母和数字,所以我更改它,现在它检查字符串show是否至少有一个字符和一个数字。

  static bool IsAlphaNumeric(string str) { bool hasDigits = false; bool hasLetters = false; foreach (char c in str) { hasDigits |= char.IsDigit(c); hasLetters |= char.IsLetter(c); if (hasDigits && hasLetters) return true; } return false; } 

结果

 My solution : 00:00:00.3900390 (Goody Gold Medal) DarinDimitrov 1 : 00:00:00.9740974 (Bronze Medal) DarinDimitrov(compiled) 2 : 00:00:00.8230823 (Silver) 

矿井是一个很重要的因素。

 private static readonly Regex _regex = new Regex( @"^(?=.*[az])(?=.*[AZ])(?=.*\d).+$", RegexOptions.Compiled); public static bool IsAlphaAndNumeric(string s) { return _regex.IsMatch(s); } 

如果您想忽略大小写,可以使用RegexOptions.Compiled | RegexOptions.IgnoreCase RegexOptions.Compiled | RegexOptions.IgnoreCase

以下不仅比其他前瞻构造更快,它(在我看来)也更接近要求:

 [a-zA-Z\d]((?<=\d)[^a-zA-Z]*[a-zA-Z]|[^\d]*\d) 

在我的(不可否认的原始测试)中,它运行的时间大约是其他正则表达式解决方案所需的一半时间,并且具有不关心输入字符串中的换行符的优点。 (如果由于某种原因它应该,显然如何包括它)。

以下是它的工作原理(以及原因):

第1步:匹配单个字符(我们称之为c ),即数字或字母。
第2步:检查c是否为数字。 如果是这样:
步骤2.1:它允许无限数量的字母,而不是一个字母,后跟一个字母。 如果匹配,我们有一个数字( c )后跟一个字母。
步骤2.2:如果c不是数字,则必须是一个字母(否则它不会匹配)。 在这种情况下,我们允许无限数量的非数字,后跟一个数字。 这意味着我们有一个字母( c )后跟一个数字。