0

実際には、ユーザーを登録するフォームと検証終了パスワードにユーザー名を含めてはならず、ユーザー名から連続した 2 文字を含めてはならないアプリに取り組んでいるという小さな問題があります。

ユーザー名 ID が「Aspnetmvc」の場合、パスワードには「Aspnetmvc」という単語全体、または asp、net、mvc などのユーザー名の一部を含めることはできません。これはカスタマイズロジックで解決できますが、私がやりたいのはプログラミングロジックで解決することですが、私がやりたいのは、この問題を正規表現で解決する方法を見つけることです。

この C# について考えている人はいますか?

4

2 に答える 2

4

非常に簡単な解決策は、ユーザー名と実名から可能なすべての 3 文字の組み合わせを抽出し、それらがパスワードの一部であるかどうかを確認するメソッドを作成することです。3 文字 (2 を超える) の各可能な部分のメソッドは、単純な拡張メソッドとして記述でき、IEnumerable.Anyメソッドを使用して、これらの部分のいずれかがパスワードの一部であるかどうかを確認できます。

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApplication5
{
    static class Program
    {
        static void Main(string[] args)
        {
            string password = "1234567890";

            string username = "125689";
            string realName = "890";

            bool usernameOk = !username.AllPartsOfLength(3)
                .Any(part => password.Contains(part));
            bool realNameOk = !realName.AllPartsOfLength(3)
                .Any(part => password.Contains(part));
        }

        public static IEnumerable<string> AllPartsOfLength(this string value, int length)
        {
            for (int startPos = 0; startPos <= value.Length - length; startPos++)
            {
                yield return value.Substring(startPos, length);
            }
            yield break;
        }
    }
}

これは、正規表現を含むどのソリューションよりも読みやすいと思います。

あなたもできる:

passwordOk = !username.AllPartsofLength(3)
    .Concat(realName.AllPartsOfLength(3))
    .Any(part => password.Contains(part));

これらは遅延評価を使用するため、最初の部分が見つかると評価が停止します。

正規表現でこれを行う必要はまったくありませんし、正当な理由もありません。使用できる唯一の式は、文字列内に 3 文字の部分が存在するかどうかをチェックする式です。そのため、文字列を 3 つの部分に分割してから式を作成し、ランタイムにそのためのステートマシンを作成させ、それを入力と照合してから式を破棄する必要があります。目前の問題に対しては高価です。

次のようになります。

IEnumerable<string> parts = username.AllPartsOfLength(3)
    .Concat(realName.AllPartsOfLength(3))
    .Select(part => Regex.Escape(part));

string regex = "(" + string.Join("|", parts) + ")";

bool isPasswordOk = !Regex.Match(regex).Success;

ベンチマークが追加されました

sln の要求に応じて、短いベンチマーク:

メソッド: StringManipulationOnly 所要時間: 26,0015ms。合格: 3333. 失敗 6666.

メソッド: RegexStringJoinAllParts 所要時間: 486,0278ms。合格: 3333. 失敗 6666.

メソッド: RegexZeroWidthPlusOneAndDotSplat 所要時間: 5686,3252ms。合格: 3333. 失敗 6666.

メソッド: RegexZeroWidth かかった時間: 2659,1521ms。合格: 3333. 失敗 6666.

編集 e.* を削除して別のテストを行いましたが、余分な . そこに保管された

メソッド: RegexZeroWidthPlusOne かかった時間: 2601,1488ms。合格: 3333. 失敗 6666.

ご覧のとおり、.*さらに 50% の遅延が発生しており、正規表現を使用して文字列を分割するすべてのソリューションは、string.Join を使用して 1 つの大きな式を作成するよりもはるかに遅くなります。明確な勝者は、正規表現を使用していないことです。

.*constantよりも遅いという事実の説明は、constant.* が最初に入力全体を取得し、次に定数を見つけるために (文字列の末尾から) バックトラックを開始しconstant、最初のものを探すだけであるという事実による可能性があります。の発生constant

簡単なテストでこれを確認できるようです (.*?の代わりに使用.*):

メソッド: RegexZeroWidthPlusOneDotSplatReluctant 所要時間: 2646,1514ms。合格: 3333. 失敗 6666.

コードにいくつかの変更を加えました。大文字と小文字の区別チェックを削除しました (OP から要求されたものではありません)。引数の検証を削除しました。コードを早期に失敗するように変更しました。これにより、異なる方法間の公正な比較が保証されます。コードはここにあります

于 2012-04-29T16:25:54.823 に答える
0

あなたは正規表現にあなたのために仕事をさせるべきです(?=(..)).

やり直し 4-29

static class Program
{
    static void Main(string[] args)
    {
        string Password = "(O*@aJY^+{PC";
        string Account  = "email@Abc.com";
        string Name     = "Ted Nelson";
        if (Password.IsNotSequentialChars(Account, 2) && Password.IsNotSequentialChars(Name, 2))
            Console.WriteLine("Passed");
        else
            Console.WriteLine("Failed");
    }

    public static bool IsNotSequentialChars(this string Src, string Dest, int check_len)
    {
        if (check_len < 1 || Src.Length < check_len) return true;
        Match m = Regex.Match(Src, "(?=(.{" + check_len + "})).");
        bool bOK = m.Success;

        while (bOK && m.Success)
        {
            // Edit: remove unnecessary '.*' from regex.
            // And btw, is regex needed at all in this case?
            bOK = !Regex.Match(Dest, "(?i)" + Regex.Escape(m.Groups[1].Value)).Success;
            if (!bOK)
                Console.WriteLine("Destination contains " + check_len + " sequential source letter(s) '" + m.Groups[1].Value + "'");
            m = m.NextMatch();
        }
        return bOK;
    }
}

ベンチマークは大歓迎です...

于 2012-04-27T22:08:28.680 に答える