diff --git a/ExportDXF/Services/FilenameTemplateParser.cs b/ExportDXF/Services/FilenameTemplateParser.cs new file mode 100644 index 0000000..de55470 --- /dev/null +++ b/ExportDXF/Services/FilenameTemplateParser.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace ExportDXF.Services +{ + public static class FilenameTemplateParser + { + private static readonly Regex PlaceholderPattern = new Regex( + @"\{(?\w+)(?::(?\d+))?\}", + RegexOptions.Compiled); + + /// + /// Evaluates a template string for a given item. + /// e.g. "4321 A01 PT{item_no:2}" with item_no=3 → "4321 A01 PT03" + /// + public static string Evaluate(string template, Item item) + { + return PlaceholderPattern.Replace(template, match => + { + var name = match.Groups["name"].Value.ToLowerInvariant(); + var padStr = match.Groups["pad"].Value; + int pad = string.IsNullOrEmpty(padStr) ? 0 : int.Parse(padStr); + + string value; + switch (name) + { + case "item_no": + value = item.ItemNo ?? "0"; + if (pad > 0) + value = value.PadLeft(pad, '0'); + break; + case "part_name": + value = item.PartName ?? ""; + break; + case "config": + value = item.Configuration ?? ""; + break; + case "material": + value = item.Material ?? ""; + break; + default: + value = match.Value; + break; + } + + return value; + }); + } + + /// + /// Extracts the literal prefix before the first placeholder. + /// Used for naming the xlsx and log files. + /// Falls back to documentName if prefix is empty. + /// + public static string GetPrefix(string template, string documentName) + { + var match = PlaceholderPattern.Match(template); + if (!match.Success) + return template.Trim(); + + var prefix = template.Substring(0, match.Index).Trim(); + if (string.IsNullOrEmpty(prefix)) + return Path.GetFileNameWithoutExtension(documentName); + + return prefix; + } + + /// + /// Validates that the template contains {item_no} to prevent filename collisions. + /// + public static bool Validate(string template, out string error) + { + error = null; + + if (string.IsNullOrWhiteSpace(template)) + { + error = "Template cannot be empty."; + return false; + } + + var hasItemNo = PlaceholderPattern.Matches(template) + .Cast() + .Any(m => m.Groups["name"].Value.Equals("item_no", StringComparison.OrdinalIgnoreCase)); + + if (!hasItemNo) + { + error = "Template must contain {item_no} or {item_no:N} to avoid filename collisions."; + return false; + } + + return true; + } + } +}