| | | 1 | | namespace LOCKnet.Core.Services; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// Parser fuer typische Copy/Paste-Formate von Recovery-/Backup-Codes. |
| | | 5 | | /// </summary> |
| | | 6 | | public static class BackupCodeParser |
| | | 7 | | { |
| | | 8 | | /// <summary> |
| | | 9 | | /// Zerlegt Rohtext in einzelne Codes. |
| | | 10 | | /// Unterstuetzt Zeilenumbrueche sowie komma-/semikolongetrennte Listen. |
| | | 11 | | /// </summary> |
| | | 12 | | /// <param name="raw">Rohtext aus Eingabe oder Zwischenablage.</param> |
| | | 13 | | /// <returns>Normalisierte Liste einzelner Codes in Einfuegereihenfolge ohne Duplikate.</returns> |
| | | 14 | | public static IReadOnlyList<string> Parse(string? raw) |
| | 3 | 15 | | { |
| | 3 | 16 | | if (string.IsNullOrWhiteSpace(raw)) |
| | 0 | 17 | | return []; |
| | | 18 | | |
| | 3 | 19 | | var result = new List<string>(); |
| | 3 | 20 | | var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
| | 3 | 21 | | var lines = raw.Replace("\r\n", "\n", StringComparison.Ordinal) |
| | 3 | 22 | | .Replace('\r', '\n') |
| | 3 | 23 | | .Split('\n', StringSplitOptions.None); |
| | | 24 | | |
| | 25 | 25 | | foreach (var line in lines) |
| | 8 | 26 | | { |
| | 8 | 27 | | if (string.IsNullOrWhiteSpace(line)) |
| | 1 | 28 | | continue; |
| | | 29 | | |
| | 7 | 30 | | var parts = line.Contains(',') || line.Contains(';') |
| | 7 | 31 | | ? line.Split([',', ';'], StringSplitOptions.None) |
| | 7 | 32 | | : [line]; |
| | | 33 | | |
| | 41 | 34 | | foreach (var part in parts) |
| | 10 | 35 | | { |
| | 10 | 36 | | var normalized = Normalize(part); |
| | 10 | 37 | | if (normalized.Length == 0) |
| | 0 | 38 | | continue; |
| | | 39 | | |
| | 10 | 40 | | if (seen.Add(normalized)) |
| | 8 | 41 | | result.Add(normalized); |
| | 10 | 42 | | } |
| | 7 | 43 | | } |
| | | 44 | | |
| | 3 | 45 | | return result; |
| | 3 | 46 | | } |
| | | 47 | | |
| | | 48 | | private static string Normalize(string value) |
| | 10 | 49 | | { |
| | 10 | 50 | | var trimmed = value.Trim(); |
| | 10 | 51 | | if (trimmed.Length == 0) |
| | 0 | 52 | | return string.Empty; |
| | | 53 | | |
| | 10 | 54 | | return string.Join(' ', trimmed.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)); |
| | 10 | 55 | | } |
| | | 56 | | } |