簡體   English   中英

將這兩個正則表達式合二為一

[英]Combining these two Regular Expressions into one

我在C#中有以下內容:

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

我想檢查參數s包含至少一個字母字符一個數字,我寫了上面的方法來做到這一點。

但是有沒有辦法將兩個正則表達式( "[a-zA-Z]+""\\d+" )組合成一個?

對於帶有LINQ的C#:

return s.Any(Char.IsDigit) && s.Any(Char.IsLetter);
@"^(?=.*[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引擎會嘗試匹配字符串中的每個點。

你可以使用[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<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)

礦井是一個很重要的因素。

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 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 )后跟一個數字。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM