diff --git a/ADO2025/PI6/Helper-2025-05-21.cs b/ADO2025/PI6/Helper-2025-05-21.cs new file mode 100644 index 0000000..dde272e --- /dev/null +++ b/ADO2025/PI6/Helper-2025-05-21.cs @@ -0,0 +1,184 @@ + +using System.Collections.ObjectModel; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; + +using Microsoft.Extensions.Logging; + +namespace File_Folder_Helper.ADO2025.PI6; + +internal static partial class Helper20250521 { + + [GeneratedRegex(@"[~\-,.0-9]")] + private static partial Regex Number(); + + [GeneratedRegex(@"[^\u0020-\u007E]")] + private static partial Regex ASCII(); + + private record Record(string Directory, string FileNameWithoutExtension); + + private record LineCheck(string[] Segments, DateTime TransactionDate, DateTime EffectiveDate) { + + internal static LineCheck Get(int dateLineSegmentCount, string datePattern, string line) { + LineCheck result; + string[] segments = line.Split(' '); + if (segments.Length >= dateLineSegmentCount + && segments[0].Length == datePattern.Length + && segments[1].Length == datePattern.Length + && DateTime.TryParseExact(segments[0], datePattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime transactionDate) + && DateTime.TryParseExact(segments[1], datePattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime effectiveDate)) { + result = new(Segments: segments, TransactionDate: transactionDate, EffectiveDate: effectiveDate); + } else { + result = new(Segments: segments, TransactionDate: DateTime.MinValue, EffectiveDate: DateTime.MinValue); + } + return result; + } + } + + private record RecordB(int I, + DateTime TransactionDate, + DateTime EffectiveDate, + string Description, + decimal WithdrawalOrDeposit, + decimal Balance); + + [JsonSourceGenerationOptions(WriteIndented = true)] + [JsonSerializable(typeof(RecordB[]))] + private partial class Helper20250521RecordB : JsonSerializerContext { + } + + internal static void MatchDirectory(ILogger logger, List args) { + Record record; + string datePattern = args[5]; + string searchPattern = args[2]; + string searchPatternB = args[3]; + string columns = args[6].Replace('~', ','); + int dateLineSegmentCount = int.Parse(args[4]); + string sourceDirectory = Path.GetFullPath(args[0].Split('~')[0]); + ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(searchPattern, sourceDirectory); + MoveMatchDirectory(searchPatternB, keyValuePairs, sourceDirectory); + ReadOnlyCollection records = GetRecords(searchPatternB, sourceDirectory, dateLineSegmentCount, datePattern, columns); + WriteRecords(sourceDirectory, records); + } + + private static ReadOnlyDictionary GetKeyValuePairs(string searchPattern, string sourceDirectory) { + Dictionary results = []; + string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories); + foreach (string file in files) { + results.Add(Path.GetFileNameWithoutExtension(file), Path.GetDirectoryName(file)); + } + return results.AsReadOnly(); + } + + private static void MoveMatchDirectory(string searchPatternB, ReadOnlyDictionary keyValuePairs, string sourceDirectory) { + string checkFile; + string fileNameWithoutExtension; + string[] files = Directory.GetFiles(sourceDirectory, searchPatternB, SearchOption.AllDirectories); + foreach (string file in files) { + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file); + if (!keyValuePairs.TryGetValue(fileNameWithoutExtension, out string? match)) + continue; + checkFile = Path.Combine(match, Path.GetFileName(file)); + if (File.Exists(checkFile)) + continue; + File.Move(file, checkFile); + } + } + + private static ReadOnlyCollection GetRecords(string searchPatternB, string sourceDirectory, int dateLineSegmentCount, string datePattern, string columns) { + List results = []; + string line; + string[] lines; + RecordB? record; + LineCheck lineCheck; + string[] files = Directory.GetFiles(sourceDirectory, searchPatternB, SearchOption.AllDirectories); + foreach (string file in files) { + lines = File.ReadAllLines(file); + for (int i = 0; i < lines.Length; i++) { + line = lines[i]; + if (string.IsNullOrEmpty(line)) { + continue; + } + lineCheck = LineCheck.Get(dateLineSegmentCount, datePattern, line); + if (lineCheck.EffectiveDate == DateTime.MinValue || lineCheck.TransactionDate == DateTime.MinValue) { + continue; + } else { + record = GetRecord(dateLineSegmentCount, datePattern, lines, i, lineCheck.Segments, lineCheck.TransactionDate, lineCheck.EffectiveDate); + if (record is not null) { + i = record.I; + results.Add(record); + } + } + } + } + return results.AsReadOnly(); + } + + private static RecordB? GetRecord(int dateLineSegmentCount, string datePattern, string[] lines, int i, string[] segments, DateTime transactionDate, DateTime effectiveDate) { + RecordB? result = null; + string line; + RecordB record; + LineCheck lineCheck; + List collection = []; + for (int j = i + 1; j < lines.Length; j++) { + line = lines[j]; + if (string.IsNullOrEmpty(line)) { + continue; + } + lineCheck = LineCheck.Get(dateLineSegmentCount, datePattern, line); + if (lineCheck.EffectiveDate == DateTime.MinValue || lineCheck.TransactionDate == DateTime.MinValue) { + collection.Add(line); + } else { + if (lineCheck.Segments.Length > dateLineSegmentCount) { + collection.Insert(0, string.Join(' ', lineCheck.Segments.Skip(2))); + } + result = GetRecord(transactionDate, effectiveDate, collection.AsReadOnly(), j - 1); + break; + } + } + if (result is null && collection.Count > 0) { + result = GetRecord(transactionDate, effectiveDate, collection.AsReadOnly(), lines.Length - 1); + } + return result; + } + + private static RecordB GetRecord(DateTime transactionDate, DateTime effectiveDate, ReadOnlyCollection collection, int i) { + RecordB? result; + List verified = []; + foreach (string check in collection) { + if (Number().Replace(check, string.Empty).Length != 0) { + verified.Clear(); + } else { + verified.Add(check); + } + if (verified.Count == 2) { + break; + } + } + if (verified.Count != 2) { + result = null; + } else { + decimal balance = decimal.Parse(verified[^1]); + decimal withdrawalOrDeposit = decimal.Parse(verified[^2]); + string description = ASCII().Replace(string.Join(' ', collection.SkipLast(2)), string.Empty); + result = new(I: i, + TransactionDate: transactionDate, + EffectiveDate: effectiveDate, + Description: description, + WithdrawalOrDeposit: withdrawalOrDeposit, + Balance: balance); + } + return result; + } + + private static void WriteRecords(string sourceDirectory, ReadOnlyCollection records) { + string json = JsonSerializer.Serialize(records.ToArray(), Helper20250521RecordB.Default.RecordBArray); + string sourceDirectoryVsCode = Path.Combine(sourceDirectory, ".vscode"); + if (!Directory.Exists(sourceDirectoryVsCode)) + _ = Directory.CreateDirectory(sourceDirectoryVsCode); + File.WriteAllText(Path.Combine(sourceDirectoryVsCode, $"{DateTime.Now.Ticks}.json"), json); + } + +} \ No newline at end of file diff --git a/Day/HelperDay.cs b/Day/HelperDay.cs index 8bbe1db..e54f274 100644 --- a/Day/HelperDay.cs +++ b/Day/HelperDay.cs @@ -163,6 +163,8 @@ internal static class HelperDay ADO2025.PI5.Helper20250505.HyperTextMarkupLanguageToPortableDocumentFormat(logger, args); else if (args[1] == "Day-Helper-2025-05-19") ADO2025.PI6.Helper20250519.LiveSync(logger, args); + else if (args[1] == "Day-Helper-2025-05-21") + ADO2025.PI6.Helper20250521.MatchDirectory(logger, args); else throw new Exception(appSettings.Company); }