From 75143153ca3dec4e69175014c5b9dc331337d90a Mon Sep 17 00:00:00 2001 From: tehtelev <50070668+tehtelev@users.noreply.github.com> Date: Fri, 2 Jan 2026 18:13:22 +0300 Subject: [PATCH] Implement optimized FillPlaceHolder method Added an optimized version of FillPlaceHolder that processes all replacements in a single pass, improving performance for placeholder replacements. --- Common/Registry/RegistryObject.cs | 106 ++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/Common/Registry/RegistryObject.cs b/Common/Registry/RegistryObject.cs index f095fbc7a..cfe76849a 100644 --- a/Common/Registry/RegistryObject.cs +++ b/Common/Registry/RegistryObject.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Linq; using System.Text.RegularExpressions; using Vintagestory.API.Datastructures; using Vintagestory.API.Util; @@ -330,6 +331,111 @@ public static string FillPlaceHolder(string input, string search, string replace return Regex.Replace(input, pattern, replace); } + + + /// + /// Fast variant of FillPlaceHolder that processes all replacements in a single pass + /// + public static string FillPlaceHolderOptimized(string input, OrderedDictionary searchReplace) + { + if (string.IsNullOrEmpty(input) || searchReplace == null || searchReplace.Count == 0) + return input; + + // Fast check without allocations + bool hasPlaceholders = false; + for (int i = 0; i < input.Length; i++) + { + if (input[i] == '{') + { + hasPlaceholders = true; + break; + } + } + if (!hasPlaceholders) return input; + + // Use a list of changes for batch replacements + var replacements = new List<(int start, int length, string value)>(); + + // Search for all placeholders + int pos = 0; + while (pos < input.Length) + { + if (input[pos] == '{') + { + int start = pos; + int end = -1; + + // Search for closing brace + for (int i = pos + 1; i < input.Length; i++) + { + if (input[i] == '}') + { + end = i; + break; + } + } + + if (end > 0) + { + string placeholder = input.Substring(start + 1, end - start - 1); + var parts = placeholder.Split('|'); + + // Search for the first matching key (in searchReplace order) + foreach (var kvp in searchReplace) + { + bool found = false; + foreach (var part in parts) + { + if (part == kvp.Key) + { + found = true; + break; + } + } + + if (found) + { + replacements.Add((start, end - start + 1, kvp.Value)); + break; + } + } + + pos = end + 1; + } + else + { + pos++; + } + } + else + { + pos++; + } + } + + // If there are no replacements, return the original string + if (replacements.Count == 0) return input; + + // Assemble the result + var result = new StringBuilder(input.Length); + int currentIndex = 0; + + foreach (var (start, length, value) in replacements.OrderBy(r => r.start)) + { + // Add text before the replacement + result.Append(input, currentIndex, start - currentIndex); + + // Add the replacement + result.Append(value); + + currentIndex = start + length; + } + + // Add the remaining text + result.Append(input, currentIndex, input.Length - currentIndex); + + return result.ToString(); + } } }