Regex Problem

  • C#
  • .NET (FX) 1.0–2.0

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Regex Problem

    Hey,

    Kann mir jemand helfen ein solches Regex-Pattern zu erstellen um mittels einer solchen Funktion

    C#-Quellcode

    1. private static bool IsValid(string pass)
    2. {
    3. }


    zu prüfen ob mein Passwort im richtigen Format ist.
    Das Passwort hat folgende Eigenschaften:

    - Es muss aus 8 Zeichen bestehen/bzw 8 Zeichen lang sein.
    - Es dürfen nur folgende Zeichen darin vorkommen : 0,1,2,3,4,5,6,7,8,9,0,A,B,C,D,E,F (ohne die Kommas)
    - Falls Buchstaben darin vorkommen müssen es Großbuchstaben sein.

    Lg
    Rikudo
    C# Developer
    Learning C++

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Rikudo“ ()

    Du willst nur Hexwerte in deinem Passwort zulassen?

    Naja, mir einer einfachen suche wäre man bei

    Quellcode

    1. ​^[0-9A-F]+$

    gelandet
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.

    C#-Quellcode

    1. private bool isValid(string pass)
    2. {
    3. if (pass.Length < 8) return false;
    4. var invalidChars = new[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'C', 'D', 'E', 'F'};
    5. return pass.ToCharArray().All(x => invalidChars.Contains(x));
    6. }
    Mfg
    Vincent

    @Higlav, Sorry das mit den acht Zeichen hatte ich nicht eingefügt und das B übersehen.
    Wobei die Frage ist ob es wirklich nicht dabei sin soll oder im Startpost einfach nur fehlt
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.

    Higlav schrieb:

    ^[0-9ACDEF]{8}$

    EDIT: @MrTrebron Das "B" ist nicht dabei und es sollen genau 8 Zeichen sein. ;)

    Whops, das hab ich ausversehen vergessen dazuzuschreiben :D
    Das B muss auch dazu ist aber ja kein Problem kann ich ja in dem Pattern grad dazufügen^^
    Danke für die schnellen antowrten an alle :D
    C# Developer
    Learning C++

    Rikudo schrieb:

    kann ich ja in dem Pattern grad dazufügen^^

    Schreib dafür doch einfach den Vorschlag von @Thunderbolt um:
    ^[0-9A-F]{8}$

    Somit sparst Du das mit den vielen Buchstaben. ;)

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    @Rikudo Wenn du Hex evaulieren möchtest, kann auch TryParse helfen. Ich weiß nur nicht, wie performant das abläuft:

    C#-Quellcode

    1. bool isValid(string pass) {
    2. int temp;
    3. return int.TryParse(pass, System.Globalization.NumberStyles.HexNumber, null, out temp);
    4. }
    Mit freundlichen Grüßen,
    Thunderbolt
    Hier meine Testergebnisse:


    TestCode

    C#-Quellcode

    1. class Program
    2. {
    3. static long timeRegexValid = 0;
    4. static long timeRegexInvalid = 0;
    5. static long timeLinqValid = 0;
    6. static long timeLinqInvalid = 0;
    7. static long timeParseValid = 0;
    8. static long timeParseInvalid = 0;
    9. static long timeRinecamoValid = 0;
    10. static long timeRinecamoInvalid = 0;
    11. static Stopwatch sRegex = new Stopwatch();
    12. static Stopwatch sLinq = new Stopwatch();
    13. static Stopwatch sParse = new Stopwatch();
    14. static Stopwatch sRinecamo = new Stopwatch();
    15. static long Freq = Stopwatch.Frequency;
    16. [STAThread]
    17. static void Main(string[] args)
    18. {
    19. Console.WriteLine("Tasks Running ...");
    20. Task Regex = Task.Factory.StartNew(delegate
    21. {
    22. for(int i = 0; i < 1000000; i++)
    23. {
    24. string pass = CreatePasswordValid();
    25. sRegex.Start();
    26. IsValidRegex(pass);
    27. timeRegexValid += sRegex.ElapsedTicks;
    28. sRegex.Reset();
    29. }
    30. for(int i = 0; i < 1000000; i++)
    31. {
    32. string pass = CreatePasswordInvalid();
    33. sRegex.Start();
    34. IsValidRegex(pass);
    35. timeRegexInvalid += sRegex.ElapsedTicks;
    36. sRegex.Reset();
    37. }
    38. });
    39. Task Linq = Task.Factory.StartNew(delegate
    40. {
    41. for(int i = 0; i < 1000000; i++)
    42. {
    43. string pass = CreatePasswordValid();
    44. sLinq.Start();
    45. IsValidLinq(pass);
    46. timeLinqValid += sLinq.ElapsedTicks;
    47. sLinq.Reset();
    48. }
    49. for(int i = 0; i < 1000000; i++)
    50. {
    51. string pass = CreatePasswordInvalid();
    52. sLinq.Start();
    53. IsValidLinq(pass);
    54. timeLinqInvalid += sLinq.ElapsedTicks;
    55. sLinq.Reset();
    56. }
    57. });
    58. Task Parse = Task.Factory.StartNew(delegate
    59. {
    60. for(int i = 0; i < 1000000; i++)
    61. {
    62. string pass = CreatePasswordValid();
    63. sParse.Start();
    64. IsValidParse(pass);
    65. timeParseValid += sParse.ElapsedTicks;
    66. sParse.Reset();
    67. }
    68. for(int i = 0; i < 1000000; i++)
    69. {
    70. string pass = CreatePasswordInvalid();
    71. sParse.Start();
    72. IsValidParse(pass);
    73. timeParseInvalid += sParse.ElapsedTicks;
    74. sParse.Reset();
    75. }
    76. });
    77. Task Rinecamo = Task.Factory.StartNew(delegate
    78. {
    79. for(int i = 0; i < 1000000; i++)
    80. {
    81. string pass = CreatePasswordValid();
    82. sRinecamo.Start();
    83. IsValidRinecamo(pass);
    84. timeRinecamoValid += sRinecamo.ElapsedTicks;
    85. sRinecamo.Reset();
    86. }
    87. for(int i = 0; i < 1000000; i++)
    88. {
    89. string pass = CreatePasswordInvalid();
    90. sRinecamo.Start();
    91. IsValidRinecamo(pass);
    92. timeRinecamoInvalid += sRinecamo.ElapsedTicks;
    93. sRinecamo.Reset();
    94. }
    95. });
    96. Task.WaitAll(Regex, Linq, Parse, Rinecamo);
    97. Console.WriteLine("After 1000000 runs each:\r\n");
    98. Console.WriteLine("Regex Valid Passwords: {0} seconds", Math.Round((double)timeRegexValid / (double)Freq,4));
    99. Console.WriteLine("Regex Invalid Passwords: {0} seconds\r\n", Math.Round((double)timeRegexInvalid / (double)Freq, 4));
    100. Console.WriteLine("Linq Valid Passwords: {0} seconds", Math.Round((double)timeLinqValid / (double)Freq, 4));
    101. Console.WriteLine("Linq Invalid Passwords: {0} seconds\r\n", Math.Round((double)timeLinqInvalid / (double)Freq, 4));
    102. Console.WriteLine("Parse Valid Passwords: {0} seconds", Math.Round((double)timeParseValid / (double)Freq, 4));
    103. Console.WriteLine("Parse Invalid Passwords: {0} seconds\r\n", Math.Round((double)timeParseInvalid / (double)Freq, 4));
    104. Console.WriteLine("Rinecamo Valid Passwords: {0} seconds", Math.Round((double)timeRinecamoValid / (double)Freq, 4));
    105. Console.WriteLine("Rinecamo Invalid Passwords: {0} seconds\r\n", Math.Round((double)timeRinecamoInvalid / (double)Freq, 4));
    106. Console.WriteLine("Frequency: {0}", Stopwatch.Frequency);
    107. Console.ReadKey(true);
    108. }
    109. public static string CreatePasswordValid(int passwordLength=8, string AllChar = "0123456789ABCDEF")
    110. {
    111. string allowedChars = AllChar;
    112. char[] chars = new char[passwordLength];
    113. var rd = new Random();
    114. for(int i = 0; i < passwordLength; i++)
    115. { chars[i] = allowedChars[rd.Next(0, allowedChars.Length)]; }
    116. return new string(chars);
    117. }
    118. public static string CreatePasswordInvalid(int passwordLength=8, string AllChar = "!\"§$%&/()=?GHIJKL")
    119. {
    120. string allowedChars = AllChar;
    121. char[] chars = new char[passwordLength];
    122. var rd = new Random();
    123. for(int i = 0; i < passwordLength; i++)
    124. { chars[i] = allowedChars[rd.Next(0, allowedChars.Length)]; }
    125. return new string(chars);
    126. }
    127. private static bool IsValidRegex(string Passwort)
    128. {
    129. return Regex.IsMatch(Passwort, "^[0-9A-F]{8}$",RegexOptions.Compiled);
    130. }
    131. private static bool IsValidLinq(string Passwort)
    132. {
    133. if(Passwort.Length < 8)
    134. return false;
    135. var invalidChars = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'C', 'D', 'E', 'F' };
    136. return Passwort.ToCharArray().All(x => invalidChars.Contains(x));
    137. }
    138. private static bool IsValidRinecamo(string Passwort)
    139. {
    140. foreach(var c in Passwort)
    141. {
    142. if((c <= 47 || c >= 58) && (c <= 64 || c >= 71))
    143. return false;
    144. }
    145. return true;
    146. }
    147. private static bool IsValidParse(string Passwort)
    148. {
    149. int temp;
    150. return int.TryParse(Passwort, System.Globalization.NumberStyles.HexNumber, null, out temp);
    151. }
    152. }

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „EaranMaleasi“ ()

    1. Deine PasswordInvalid-Methode sieht genauso aus wie die PassworValid-Methode
    2. Ist, was meinen PC angeht, am schnellsten.

    C#-Quellcode

    1. foreach (var c in Passwort) {
    2. if ((c <= 47 || c >= 58) && (c <= 64 || c >= 71)) return false;
    3. }
    4. return true;

    3. RegexOptions.Compiled ;)
    @EaranMaleasi
    Ich habe den Test gerade selbst mal gemacht, allerdings mit 100.000 Durchläufen und ich war erstaunt:


    Ich habe mir folgendes überlegt: Ich habe mal gehört, dass Linq langsamer ist, als wenn man es selbst mit einer ForEach-Schleife macht (keine Ahnung, was die machen). Die ForEach-Methode sieht so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. private static bool IsValidForEach(string pass)
    2. {
    3. if (pass.Length < 8) return false;
    4. foreach (var c in pass.ToCharArray())
    5. {
    6. if (!validChars.Contains(c)) return false;
    7. }
    8. return true;
    9. }


    Wie man auch sehen kann, wird jetzt nicht jedes Mal dieses Array erstellt (ist einfach nur Speicherverschwendung), sondern es ist einfach eine statische, ReadOnly Variable. Das ist der komplette Code:
    Spoiler anzeigen

    C#-Quellcode

    1. class Program
    2. {
    3. private static readonly char[] validChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'C', 'D', 'E', 'F' };
    4. static void Main(string[] args)
    5. {
    6. var stopwatch = new Stopwatch();
    7. long all = 0;
    8. const double loops = 100000;
    9. var password = CreatePasswordValid();
    10. Console.WriteLine("===================== Valid Password: {0} =====================", password);
    11. for (int i = 0; i < loops; i++)
    12. {
    13. stopwatch.Start();
    14. IsValidLinq(password);
    15. stopwatch.Stop();
    16. all += stopwatch.ElapsedTicks;
    17. stopwatch.Reset();
    18. }
    19. Console.WriteLine("Linq: " + (all / loops));
    20. all = 0;
    21. for (int i = 0; i < loops; i++)
    22. {
    23. stopwatch.Start();
    24. IsValidForEach(password);
    25. stopwatch.Stop();
    26. all += stopwatch.ElapsedTicks;
    27. stopwatch.Reset();
    28. }
    29. Console.WriteLine("ForEach: " + (all / loops));
    30. all = 0;
    31. for (int i = 0; i < loops; i++)
    32. {
    33. stopwatch.Start();
    34. IsValidRegex(password);
    35. stopwatch.Stop();
    36. all += stopwatch.ElapsedTicks;
    37. stopwatch.Reset();
    38. }
    39. Console.WriteLine("Regex: " + (all / loops));
    40. password = CreatePasswordInvalid();
    41. Console.WriteLine("===================== Invalid Password: {0} =====================", password);
    42. all = 0;
    43. for (int i = 0; i < loops; i++)
    44. {
    45. stopwatch.Start();
    46. IsValidLinq(password);
    47. stopwatch.Stop();
    48. all += stopwatch.ElapsedTicks;
    49. stopwatch.Reset();
    50. }
    51. Console.WriteLine("Linq: " + (all / loops));
    52. all = 0;
    53. for (int i = 0; i < loops; i++)
    54. {
    55. stopwatch.Start();
    56. IsValidForEach(password);
    57. stopwatch.Stop();
    58. all += stopwatch.ElapsedTicks;
    59. stopwatch.Reset();
    60. }
    61. Console.WriteLine("ForEach: " + (all / loops));
    62. all = 0;
    63. for (int i = 0; i < loops; i++)
    64. {
    65. stopwatch.Start();
    66. IsValidRegex(password);
    67. stopwatch.Stop();
    68. all += stopwatch.ElapsedTicks;
    69. stopwatch.Reset();
    70. }
    71. Console.WriteLine("Regex: " + (all / loops));
    72. password = "garcon";
    73. Console.WriteLine("===================== Too short password: {0} =====================", password);
    74. all = 0;
    75. for (int i = 0; i < loops; i++)
    76. {
    77. stopwatch.Start();
    78. IsValidLinq(password);
    79. stopwatch.Stop();
    80. all += stopwatch.ElapsedTicks;
    81. stopwatch.Reset();
    82. }
    83. Console.WriteLine("Linq: " + (all / loops));
    84. all = 0;
    85. for (int i = 0; i < loops; i++)
    86. {
    87. stopwatch.Start();
    88. IsValidForEach(password);
    89. stopwatch.Stop();
    90. all += stopwatch.ElapsedTicks;
    91. stopwatch.Reset();
    92. }
    93. Console.WriteLine("ForEach: " + (all / loops));
    94. all = 0;
    95. for (int i = 0; i < loops; i++)
    96. {
    97. stopwatch.Start();
    98. IsValidRegex(password);
    99. stopwatch.Stop();
    100. all += stopwatch.ElapsedTicks;
    101. stopwatch.Reset();
    102. }
    103. Console.WriteLine("Regex: " + (all / loops));
    104. Console.ReadKey();
    105. }
    106. private static bool IsValidLinq(string pass)
    107. {
    108. if (pass.Length < 8) return false;
    109. return pass.ToCharArray().All(c => validChars.Contains(c));
    110. }
    111. private static bool IsValidForEach(string pass)
    112. {
    113. if (pass.Length < 8) return false;
    114. foreach (var c in pass.ToCharArray())
    115. {
    116. if (!validChars.Contains(c)) return false;
    117. }
    118. return true;
    119. }
    120. private static bool IsValidRegex(string pass)
    121. {
    122. return Regex.IsMatch(pass, "^[0-9ACDEF]{8}$");
    123. }
    124. public static string CreatePasswordValid(int passwordLength = 8)
    125. {
    126. var result = new char[passwordLength];
    127. var rd = new Random();
    128. for (int i = 0; i < passwordLength; i++)
    129. { result[i] = validChars[rd.Next(0, validChars.Length)]; }
    130. return new string(result);
    131. }
    132. public static string CreatePasswordInvalid(int passwordLength = 9)
    133. {
    134. var garcon = "safiau&fasjif98´7o6".ToCharArray();
    135. var result = new char[passwordLength];
    136. var rd = new Random();
    137. for (int i = 0; i < passwordLength; i++)
    138. { result[i] = garcon[rd.Next(0, garcon.Length)]; }
    139. return new string(result);
    140. }
    141. }


    Also: ForEach ist am schnellsten! Ich bin so dumm, habe gar nicht gesehen, dass Parse noch schneller ist... Egal, angenommen, man möchte sich nicht nur auf gültige Hex-Buchstaben beschränken.
    Mfg
    Vincent

    EaranMaleasi schrieb:

    Und nu fehlt nur noch ein Geschwindigkeitsvergleich
    Was soll das bringen?
    Ist etwa vorgesehen, 100000 Pasworte auf einmal zu validieren?

    Andernfalls ist die Geschwindigkeit malwieder vollkommen irrelevant.

    Weil 10000 passworte würden im langsamsten Fall 0,3Sekunden brauchen, und wären im schnellsten Fall 0,2s schneller. wow!

    Nur wo nehmen wir jetzt 10000 Passworte her?
    Was das bringen soll?
    Es zeigt uns und anderen welche Methode in diesem Kontext am schnellsten ist.
    Wenn bei dir für so was jegliches Interesse fehlt, kannst du uns ja in Zukunft mit deinen unnötigen Beiträgen verschonen.
    Bei aller Liebe EDR, aber nein, einfach nein.
    naja, mein Beitrag ist eben nicht unnötig.
    Ich weise darauf hin, dass solche Geschwindigkeits-Optimierungen unnötig sind.
    Weil manch einer legt da viel Brain-Power rein, und es bringt nichts. Und das muss man sich klar machen.
    Oft verschlechtert sich gar die Lesbarkeit des Codes, und dann hat man eine Lösung, die zwar schneller ist (was ja nix bringt), aber schlechter wartbar - was ein deutlicher Nachteil ist.
    Ergibt in Summe eine Verschlechterung, von der ganz eindeutig abzuraten ist.
    So auch hier: Nach Geschwindigkeit würde man Foreach wählen, aber nach Lesbarkeit ist das die schlechteste Lösung, und also die falsche, denn Programmier-Prinzip: von 2 verschieden guten Lösungen ist nur die beste richtig.

    Und das erkennt ihr nicht, und deshalb ist nötig, dass ich euch vor dieser Denke warne, die den Rules Of Optimization zuwiderläuft.
    Mir persönlich ging es nur darum die Frage der Performance von @Thunderbolt zu beantworten. Klar, für Passwordvalidierungen mag das vielleicht nicht so nützlich sein, (einmal durch ne mehrere GB große Login-Daten-DB laufen lassen vielleicht?) aber es gibt bestimmt Bereiche, in denen mehrere Millionen von Datensätzen verglichen werden müssen. Ist dann eben praktisch wenns nur 0,2 Sekunden dauert anstatt 1,x Sekunden je Million.

    Habe nun meinen Code nach den Punkten von @Rinecamo angepasst und den Screenshot aktualisiert.
    Jo, generell die Geschwindigkeit verschiedener String-Verarbeitungs-Ansätze zu untersuchen findich durchaus sinnvoll.

    Kann einem ja helfen, wenn mal Performance-Probleme auftreten.

    kann man sich auch merken, welche Ansätze das sind:
    • Regex
    • mit Schleifen die Zeichen durchlaufen
    • Linq
    • TryParse - bei geeigneten String-Daten
    Und die good old Schleifen waren die schnellsten, mit bis zu Faktor 3, oder?