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

时间:2010-01-27 09:19:49

标签: c# regex

我在C#中有以下内容:

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

我想检查参数s是否包含至少一个字母字符一位数,我写了上述方法。

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

6 个答案:

答案 0 :(得分:12)

对于带有LINQ的C#:

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

答案 1 :(得分:11)

@"^(?=.*[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)

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

答案 2 :(得分:3)

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

答案 3 :(得分:3)

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

    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<string> 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 = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\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)

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

答案 4 :(得分:2)

private static readonly Regex _regex = new Regex(
    @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", RegexOptions.Compiled);

public static bool IsAlphaAndNumeric(string s)
{
    return _regex.IsMatch(s);
}

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

答案 5 :(得分:0)

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

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

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

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

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