手册数值改为占位符,渲染时从 Tuning 取值;加规则文件和测试

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-04 12:45:29 +08:00
1 parent 38f9ea9daf
commit d28ca4e50c
6 files changed
+94 -3

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
using System;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Decentralized.Domain
{
/// <summary>
/// 文本里的数值占位符:<c>{Name}</c>、<c>{Name:%}</c>、<c>{Name[2]:%}</c>,也可以走嵌套类 <c>{Section.Name}</c>。
/// 手册等说明文字不直接写数字,渲染时从 <see cref="Tuning"/> 取值,数值一改文字跟着变。
/// <c>%</c> 把小数按百分比显示(0.03 → 3%);不带格式时去掉多余的零。
/// </summary>
public static class TuningText
{
private static readonly Regex Placeholder = new Regex(@"\{([A-Za-z0-9_.]+)(?:\[(\d+)\])?(?::(%))?\}", RegexOptions.Compiled);
public static string Render(string text)
{
if (string.IsNullOrEmpty(text)) return text;
return Placeholder.Replace(text, m => TryValue(m.Groups[1].Value, m.Groups[2].Success ? int.Parse(m.Groups[2].Value) : -1, out var v)
? Format(v, m.Groups[3].Success)
: m.Value);
}
/// <summary>文本里取不到值的占位符(测试用)。</summary>
public static System.Collections.Generic.List<string> Unresolved(string text)
{
var bad = new System.Collections.Generic.List<string>();
foreach (Match m in Placeholder.Matches(text ?? ""))
if (!TryValue(m.Groups[1].Value, m.Groups[2].Success ? int.Parse(m.Groups[2].Value) : -1, out _)) bad.Add(m.Value);
return bad;
}
private static string Format(double v, bool percent)
{
if (percent) v *= 100;
return Math.Round(v, 4).ToString("0.####", CultureInfo.InvariantCulture) + (percent ? "%" : "");
}
private static bool TryValue(string path, int index, out double value)
{
value = 0;
var type = typeof(Tuning);
var parts = path.Split('.');
for (int i = 0; i < parts.Length - 1; i++)
{
type = type.GetNestedType(parts[i], BindingFlags.Public | BindingFlags.Static);
if (type == null) return false;
}
var field = type.GetField(parts[parts.Length - 1], BindingFlags.Public | BindingFlags.Static);
if (field == null) return false;
var raw = field.GetValue(null);
if (raw is Array arr)
{
if (index < 0 || index >= arr.Length) return false;
raw = arr.GetValue(index);
}
else if (index >= 0) return false;
try { value = Convert.ToDouble(raw, CultureInfo.InvariantCulture); return true; }
catch (Exception) { return false; }
}
}
}