代码之家  ›  专栏  ›  技术社区  ›  Andreas Grech

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

  •  11
  • Andreas Grech  · 技术社区  · 14 年前

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

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

    但是有没有办法把这两个正则表达式结合起来呢( "[a-zA-Z]+" "\d+" )变成一个?

    6 回复  |  直到 14 年前
        1
  •  12
  •   gnarf    14 年前
    @"^(?=.*[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
  •  15
  •   Kobi    14 年前

    对于具有LINQ的C#:

    return s.Any(Char.IsDigit) && s.Any(Char.IsLetter);
    
        3
  •  3
  •   Anonymous    14 年前

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

        4
  •  3
  •   particle    14 年前

    这不完全是你想要的,但我有更多的时间。下面的代码应该比正则表达式工作得更快。

        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的ad不正确。在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)
    

    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提到我的算法有问题后,它检查字符串是否只由字母和数字组成,所以我更改了它,现在它检查字符串显示是否至少有一个字符和一个数字。

        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)
    

    我的很快。

        5
  •  2
  •   Darin Dimitrov    14 年前
    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 .

        6
  •  0
  •   Alan Moore Chris Ballance    14 年前

    以下内容不仅比其他前瞻性构造更快,而且(在我看来)更接近需求:

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

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

    步骤1:它匹配单个字符(我们称之为 )那是一个数字或一个字母。
    C
    步骤2.1:允许不限数量的非字母字符,后跟单个字母。如果匹配,我们有一个数字( )然后是一封信。
    步骤2.2:如果 C C )后面跟着一个数字。