/// <summary> /// Generate a name for a new object that is guaranteed to be unique for the provided "contains predicate". To generate such name, a base name and a pattern for variations must be provided. /// </summary> /// <param name="baseName">The base name used to generate the new name. If the name is available in the collection, it will be returned as-is. Otherwise, a name following the given pattern will be returned.</param> /// <param name="containsDelegate">The delegate used to determine if the asset is already existing</param> /// <param name="namePattern">The pattern used to generate the new name, when the base name is unavailable. This pattern must contains the token '{0}' that will be replaced by the base name, and the token '{1}' that will be replaced by the smallest numerical value that can generate an available name, starting from 2. If null, <see cref="DefaultNamePattern"/> will be used instead.</param> /// <returns><see cref="baseName"/> if the "contains predicate" returns false. Otherwise, a string formatted with <see cref="namePattern"/>, using <see cref="baseName"/> as token '{0}' and the smallest numerical value that can generate an available name, starting from 2</returns> public static string ComputeNewName(string baseName, ContainsLocationDelegate containsDelegate, string namePattern = null) { if (baseName == null) { throw new ArgumentNullException(nameof(baseName)); } if (namePattern == null) { namePattern = DefaultNamePattern; } if (!namePattern.Contains("{0}") || !namePattern.Contains("{1}")) { throw new ArgumentException(@"This parameter must be a formattable string containing '{0}' and '{1}' tokens", nameof(namePattern)); } // Initialize counter var counter = 1; // Checks whether baseName already 'implements' the namePattern var match = Regex.Match(baseName, Regex.Escape(namePattern).Replace(@"\{0}", @"(.*)").Replace(@"\{1}", @"(\d+)")); if (match.Success && match.Groups.Count >= 3) { // if so, extract the base name and the current counter baseName = match.Groups[1].Value; counter = Int32.Parse(match.Groups[2].Value); } // Compute name var result = baseName; while (containsDelegate(result)) { result = string.Format(namePattern, baseName, ++counter); } return(result); }
public static string ComputeNewName([NotNull] string baseName, [NotNull] ContainsLocationDelegate containsDelegate, string namePattern = null) { if (baseName == null) { throw new ArgumentNullException(nameof(baseName)); } if (containsDelegate == null) { throw new ArgumentNullException(nameof(containsDelegate)); } if (namePattern == null) { namePattern = DefaultNamePattern; } if (!namePattern.Contains("{0}") || !namePattern.Contains("{1}")) { throw new ArgumentException(@"This parameter must be a formattable string containing '{0}' and '{1}' tokens", nameof(namePattern)); } // First check if the base name itself is ok if (!containsDelegate(baseName)) { return(baseName); } // Initialize counter var counter = 1; // Checks whether baseName already 'implements' the namePattern var match = Regex.Match(baseName, $"^{Regex.Escape(namePattern).Replace(@"\{0}", @"(.*)").Replace(@"\{1}", @"(\d+)")}$"); if (match.Success && match.Groups.Count >= 3) { // if so, extract the base name and the current counter var intValue = int.Parse(match.Groups[2].Value); // Ensure there is no leading 0 messing around if (intValue.ToString() == match.Groups[2].Value) { baseName = match.Groups[1].Value; counter = intValue; } } // Compute name string result; do { result = string.Format(namePattern, baseName, ++counter); }while (containsDelegate(result)); return(result); }
/// <summary> /// Generate a name for a new object that is guaranteed to be unique for the provided "contains predicate". To generate such name, a base name and a pattern for variations must be provided. /// </summary> /// <param name="baseName">The base name used to generate the new name. If the name is available in the collection, it will be returned as-is. Otherwise, a name following the given pattern will be returned.</param> /// <param name="containsDelegate">The delegate used to determine if the asset is already existing</param> /// <param name="namePattern">The pattern used to generate the new name, when the base name is unavailable. This pattern must contains the token '{0}' that will be replaced by the base name, and the token '{1}' that will be replaced by the smallest numerical value that can generate an available name, starting from 2. If null, <see cref="DefaultNamePattern"/> will be used instead.</param> /// <returns><see cref="baseName"/> if the "contains predicate" returns false. Otherwise, a string formatted with <see cref="namePattern"/>, using <see cref="baseName"/> as token '{0}' and the smallest numerical value that can generate an available name, starting from 2</returns> public static string ComputeNewName(string baseName, ContainsLocationDelegate containsDelegate, string namePattern = null) { if (baseName == null) { throw new ArgumentNullException(nameof(baseName)); } if (namePattern == null) { namePattern = DefaultNamePattern; } if (!namePattern.Contains("{0}") || !namePattern.Contains("{1}")) { throw new ArgumentException(@"This parameter must be a formattable string containing '{0}' and '{1}' tokens", nameof(namePattern)); } string result = baseName; int counter = 1; while (containsDelegate(result)) { result = string.Format(namePattern, baseName, ++counter); } return(result); }