C# 模板占位符字典映射替换异常,无法生成正确文件头字符串
问题产生的核心原因
- 字符串重复拼接:每次匹配到闭合的
#分隔符时,代码调用str.Remove(i + 1)获取了从字符串开头到当前位置的全部内容,直接追加到结果串中,导致前面的内容被反复拼接,这是输出出现大量重复片段的根本原因。 - 普通字符遗漏追加:不在
#占位符范围内的普通字符,没有任何逻辑追加到结果串,最终输出会缺失大量非占位符内容。 - 字典查询大小写不匹配:你存在
headerCdataIndexKeyVals里的Key是大小写混合的,但查询时调用了headerSubstring.ToUpper(),除非你存Key的时候也统一转大写,否则根本匹配不到对应值。 - 占位符截取逻辑错误:WSM分支的
str.Remove(len + 1)截取长度完全错误,无法正确替换#WSM#占位符。 - 未覆盖未匹配占位符的处理逻辑:你要求未匹配到Key的占位符替换为空,现有逻辑只追加了闭合分隔符,不会删除整个占位符。
修复后的栈实现代码
public static string FindSubsInDelimetersAndReturn(string str, char openDelimiter, char closeDelimiter, HeaderMapperData mapperData ) { StringBuilder newString = new StringBuilder(); int lastAppendPos = 0; Stack<int> dels = new Stack<int>(); for (int i = 0; i < str.Length; i++) { if (str[i] == openDelimiter && dels.Count == 0) { // 先追加占位符之前的普通字符 newString.Append(str.Substring(lastAppendPos, i - lastAppendPos)); dels.Push(i); } else if (str[i] == closeDelimiter && dels.Count > 0) { int openPos = dels.Pop(); string placeholder = str.Substring(openPos + 1, i - openPos - 1); string replaceVal = string.Empty; // 处理匹配逻辑 if (placeholder == "WSM" && closeDelimiter == '#') { replaceVal = ""; } else if (mapperData.HeaderCdataIndexKeyVals.TryGetValue(placeholder.ToLower(), out int index)) { string[] parts = placeholder.Split('.'); if (parts.Length >= 2) { string arrayKey = parts[1].ToLower(); if (placeholder.Contains("container.context", StringComparison.OrdinalIgnoreCase) && parts.Length >=3) { arrayKey = $"{parts[1].ToLower()}.{parts[2].ToLower()}"; } if (mapperData.HeaderCdataArrayKeyVals.TryGetValue(arrayKey, out List<string> valList) && index < valList.Count) { replaceVal = valList[index]; } } } // 追加替换后的值 newString.Append(replaceVal); lastAppendPos = i + 1; } } // 追加最后一个占位符后的剩余字符 newString.Append(str.Substring(lastAppendPos)); return newString.ToString(); }
使用前请先把headerCdataIndexKeyVals的所有Key统一转成小写存储,和查询逻辑对齐。
更简洁的实现方式
因为你的占位符是#包裹且不存在嵌套场景,完全不需要用栈处理,直接用正则匹配替换即可,逻辑更简洁不易出错:
using System.Text.RegularExpressions; // 预编译正则匹配所有#包裹的占位符 private static readonly Regex PlaceholderRegex = new Regex(@"#([^#]+)#", RegexOptions.Compiled); public static string ReplaceHeaderPlaceholders(string str, HeaderMapperData mapperData) { return PlaceholderRegex.Replace(str, match => { string placeholder = match.Groups[1].Value; if (placeholder == "WSM") { return ""; } if (!mapperData.HeaderCdataIndexKeyVals.TryGetValue(placeholder.ToLower(), out int index)) { return ""; } string[] parts = placeholder.Split('.'); if (parts.Length < 2) { return ""; } string arrayKey = parts[1].ToLower(); if (placeholder.Contains("container.context", StringComparison.OrdinalIgnoreCase) && parts.Length >=3) { arrayKey = $"{parts[1].ToLower()}.{parts[2].ToLower()}"; } if (mapperData.HeaderCdataArrayKeyVals.TryGetValue(arrayKey, out List<string> valList) && index < valList.Count) { return valList[index]; } return ""; }); }
该实现逐行处理时仅对当前行做一次正则匹配,不会产生全量文件解析的性能损耗,同时满足占位符无匹配时返回空的要求。
内容的提问来源于stack exchange,提问作者dozie419
相关产品推荐
相关产品推荐

