读取C++头文件#define遇字典重复键,保存格式异常技术问询
解决你的C++头文件常量编辑器问题
嘿,我看你遇到了两个头疼的问题,咱们一个个来搞定:
问题1:字典重复键错误
这个错误是因为你的头文件里存在重复的#define宏定义,比如同一个常量被定义了多次,而ToDictionary方法不允许键重复。
你原来的loadweapon方法直接把匹配到的结果转成字典,一旦有重复键就会炸。咱们可以改成手动构建字典,保留最后一次出现的定义(这也是C++预处理的逻辑,后面的定义会覆盖前面的):
public void loadweapon() { this.tokens = new Dictionary<string, string>(); var lines = File.ReadLines(this.file); // 先保存原始文件内容,后续保存时可以参考(或者直接在Save里重新读取) this.header = string.Join(Environment.NewLine, lines); foreach (var line in lines) { var match = Regex.Match(line, @"^\s*#define\s+(.+?)(\s+(.+?))?((\s*//)|$)"); if (match.Success && match.Groups[3].Success) { var key = match.Groups[1].Value.Trim(); var value = match.Groups[3].Value.Trim(); // 如果键已存在,直接覆盖(模拟C++宏的覆盖逻辑) if (tokens.ContainsKey(key)) { tokens[key] = value; } else { tokens.Add(key, value); } } } }
这样既避免了重复键错误,还完全符合C++的宏处理规则。
问题2:保存文件格式混乱
你现在的Save方法有两个核心问题:
header变量根本没赋值(原来的代码里只声明了没初始化),导致写入空内容;- 写入的格式完全搞反了,应该是
#define 键 值而不是键#define 值,而且丢失了原始文件里的注释、空行和其他非#define内容。
咱们修改Save方法,只替换原始文件中对应的#define行,而不是重新生成整个文件,这样就能完美保留原始格式:
public void Save(string file) { var lines = File.ReadAllLines(file).ToList(); for (int i = 0; i < lines.Count; i++) { var line = lines[i]; var match = Regex.Match(line, @"^\s*#define\s+(.+?)(\s+(.+?))?((\s*//).*)?$"); if (match.Success && match.Groups[3].Success) { var key = match.Groups[1].Value.Trim(); if (tokens.TryGetValue(key, out var newValue)) { // 保留行首的缩进空格,替换宏的值部分,同时保留行尾注释 var prefix = line.Substring(0, match.Groups[1].Index); var comment = match.Groups[4].Value; lines[i] = $"{prefix}#define {key} {newValue}{comment}"; } } } File.WriteAllLines(file, lines); }
这个方法会遍历原始文件的每一行,只修改匹配到的#define行,替换成新的值,同时保留原始的缩进、行尾注释和其他所有内容,格式再也不会乱了。
另外提个小优化:你的Search方法可以直接用字典的TryGetValue,比foreach遍历高效多了:
public string Search(string name) { tokens.TryGetValue(name, out var value); return value; }
这样代码更简洁,性能也更好。
内容的提问来源于stack exchange,提问作者Yuuta Togashi
相关产品推荐
相关产品推荐

