如何根据标签解析十六进制字符串并生成符合要求的带标签结构化输出
如何根据标签解析十六进制字符串并生成符合要求的带标签结构化输出
我完全懂你现在的烦恼——用一堆零散的状态变量和goto写出来的代码不仅看着乱,还容易在嵌套标签的缩进、闭合时机上出问题,调试起来也头大。针对这种嵌套式的标签结构解析,递归是最适合的解决方案,能让逻辑瞬间清晰,还能轻松保证输出的结构完全符合预期。
核心思路:用递归处理嵌套层级
你的十六进制字符串本质是一个嵌套的树形结构(L标签是节点,包含若干子元素;A标签是叶子节点),递归天然适合处理这种层级关系——每遇到一个L标签,就递归处理它的所有子元素,处理完再闭合标签,缩进也能跟着层级自动调整,完全不用手动维护一堆状态变量。
优化后的完整实现
我们先把输入字符串拆分成单个十六进制令牌的列表,避免频繁的字符串截取操作,然后用递归函数逐个解析:
using System; using System.Text; using System.Collections.Generic; class HexParser { static void Main() { string inputStr = "01 04 41 03 78 79 7A 01 04 01 00 41 07 34 35 36 20 37 38 39 01 01 41 03 31 32 33 01 00 41 03 61 62 63 01 00"; var tokens = inputStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries).ToList(); int currentIndex = 0; var resultBuilder = new StringBuilder(); ParseToken(tokens, ref currentIndex, 0, resultBuilder); // 加上结尾的点 resultBuilder.Append("."); Console.WriteLine(resultBuilder.ToString()); } /// <summary> /// 递归解析令牌 /// </summary> /// <param name="tokens">十六进制令牌列表</param> /// <param name="index">当前解析的索引(引用传递,跟踪位置)</param> /// <param name="indentLevel">当前缩进层级</param> /// <param name="builder">输出字符串构建器</param> static void ParseToken(List<string> tokens, ref int index, int indentLevel, StringBuilder builder) { if (index >= tokens.Count) return; string currentToken = tokens[index]; string indent = new string(' ', indentLevel * 2); // 每层缩进2个空格 switch (currentToken) { case "01": // L标签 index++; int listCount = Convert.ToInt32(tokens[index], 16); index++; // 输出L标签开头 builder.AppendLine($"{indent}<L"); // 递归处理listCount个子元素 for (int i = 0; i < listCount; i++) { ParseToken(tokens, ref index, indentLevel + 1, builder); } // 输出L标签结尾 builder.AppendLine($"{indent}>"); break; case "41": // A标签 index++; int charCount = Convert.ToInt32(tokens[index], 16); index++; if (charCount == 0) { builder.AppendLine($"{indent}<A>"); } else { StringBuilder asciiStr = new StringBuilder(); for (int i = 0; i < charCount; i++) { byte hexByte = Convert.ToByte(tokens[index], 16); asciiStr.Append(Convert.ToChar(hexByte)); index++; } builder.AppendLine($"{indent}<A \"{asciiStr.ToString()}\">"); } break; default: // 遇到未知令牌,直接跳过(可根据需求加错误处理) index++; break; } } }
为什么这个方案更好?
- 逻辑清晰:递归函数只负责处理当前层级的标签,嵌套关系由递归调用自然维护,完全不需要
_first_list、_space_num这类容易混乱的状态变量。 - 易于维护:如果后续要新增标签类型,只需要在
switch里加一个分支即可,不用修改大量零散的状态判断。 - 格式准确:缩进层级由
indentLevel参数直接控制,每个标签的开头和闭合都严格对应,不会出现缩进错误或者标签不匹配的问题。 - 性能更优:用
StringBuilder拼接字符串,比反复拼接string高效得多;令牌列表的方式也避免了原代码中频繁的Substring操作。
运行这段代码,就能得到你期望的结构化输出啦~
备注:内容来源于stack exchange,提问作者Headshot
相关产品推荐
相关产品推荐

