Skip to content

Commit b49100e

Browse files
committed
perf(options): 优化 BuildBorder 并改进宽字符判断
- 使用 string.Create 单次分配优化 BuildBorder 字符串生成 - 提取 IsWideCharacter 方法,扩展 Unicode 范围覆盖更多语言 - 消除重复的宽字符判断代码,提高可维护性 - 解决 L-002: BuildBorder 字符串优化 - 解决 L-007: 宽字符判断不完整
1 parent 67c5cf1 commit b49100e

1 file changed

Lines changed: 113 additions & 49 deletions

File tree

GameFrameX.Foundation.Options/OptionsDebugger.cs

Lines changed: 113 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -219,16 +219,34 @@ public static void PrintParsedOptions<T>(T options) where T : class
219219

220220
string BuildBorder(char left, char sep, char right, char fill)
221221
{
222-
return string.Concat(
223-
left,
224-
new string(fill, nameWidth + 2), sep,
225-
new string(fill, valueWidth + 2), sep,
226-
new string(fill, requiredWidth + 2), sep,
227-
new string(fill, typeWidth + 2), sep,
228-
new string(fill, descWidth + 2), sep,
229-
new string(fill, defaultWidth + 2),
230-
right
231-
);
222+
// 使用 string.Create 优化:单次分配创建边框字符串
223+
// Use string.Create for optimization: create border string with single allocation
224+
int totalLength = 1 + (nameWidth + 2) + 1 + (valueWidth + 2) + 1 + (requiredWidth + 2) + 1 + (typeWidth + 2) + 1 + (descWidth + 2) + 1 + (defaultWidth + 2) + 1;
225+
return string.Create(totalLength, (left, sep, right, fill, nameWidth, valueWidth, requiredWidth, typeWidth, descWidth, defaultWidth), static (span, state) =>
226+
{
227+
int pos = 0;
228+
var (l, s, r, f, nw, vw, rw, tw, dw, dfw) = state;
229+
230+
span[pos++] = l;
231+
span.Slice(pos, nw + 2).Fill(f);
232+
pos += nw + 2;
233+
span[pos++] = s;
234+
span.Slice(pos, vw + 2).Fill(f);
235+
pos += vw + 2;
236+
span[pos++] = s;
237+
span.Slice(pos, rw + 2).Fill(f);
238+
pos += rw + 2;
239+
span[pos++] = s;
240+
span.Slice(pos, tw + 2).Fill(f);
241+
pos += tw + 2;
242+
span[pos++] = s;
243+
span.Slice(pos, dw + 2).Fill(f);
244+
pos += dw + 2;
245+
span[pos++] = s;
246+
span.Slice(pos, dfw + 2).Fill(f);
247+
pos += dfw + 2;
248+
span[pos] = r;
249+
});
232250
}
233251

234252

@@ -306,19 +324,7 @@ static string TruncPadDisplay(string s, int width)
306324
var sb = new StringBuilder();
307325
foreach (var rune in s.EnumerateRunes())
308326
{
309-
int v = rune.Value;
310-
bool wide =
311-
(v >= 0x4E00 && v <= 0x9FFF) ||
312-
(v >= 0x3400 && v <= 0x4DBF) ||
313-
(v >= 0x3000 && v <= 0x303F) ||
314-
(v >= 0x3040 && v <= 0x309F) ||
315-
(v >= 0x30A0 && v <= 0x30FF) ||
316-
(v >= 0xAC00 && v <= 0xD7AF) ||
317-
(v >= 0xF900 && v <= 0xFAFF) ||
318-
(v >= 0xFF01 && v <= 0xFF60) ||
319-
(v >= 0xFFE0 && v <= 0xFFE6) ||
320-
(v >= 0x1F300 && v <= 0x1FAFF);
321-
int rw = wide ? 2 : 1;
327+
int rw = IsWideCharacter(rune.Value) ? 2 : 1;
322328
if (w + rw > width)
323329
{
324330
if (width > 1)
@@ -356,19 +362,7 @@ static List<string> WrapToDisplayLines(string s, int width)
356362
int w = 0;
357363
foreach (var rune in s.EnumerateRunes())
358364
{
359-
int v = rune.Value;
360-
bool wide =
361-
(v >= 0x4E00 && v <= 0x9FFF) ||
362-
(v >= 0x3400 && v <= 0x4DBF) ||
363-
(v >= 0x3000 && v <= 0x303F) ||
364-
(v >= 0x3040 && v <= 0x309F) ||
365-
(v >= 0x30A0 && v <= 0x30FF) ||
366-
(v >= 0xAC00 && v <= 0xD7AF) ||
367-
(v >= 0xF900 && v <= 0xFAFF) ||
368-
(v >= 0xFF01 && v <= 0xFF60) ||
369-
(v >= 0xFFE0 && v <= 0xFFE6) ||
370-
(v >= 0x1F300 && v <= 0x1FAFF);
371-
int rw = wide ? 2 : 1;
365+
int rw = IsWideCharacter(rune.Value) ? 2 : 1;
372366

373367
if (w + rw > width)
374368
{
@@ -402,6 +396,7 @@ static List<string> WrapToDisplayLines(string s, int width)
402396
}
403397

404398
// 显示宽度相关函数:中文及全角字符按双列宽处理
399+
// Display width function: CJK and fullwidth characters are treated as double-width
405400
static int GetDisplayWidth(string s)
406401
{
407402
if (string.IsNullOrEmpty(s))
@@ -412,24 +407,93 @@ static int GetDisplayWidth(string s)
412407
int w = 0;
413408
foreach (var rune in s.EnumerateRunes())
414409
{
415-
int v = rune.Value;
416-
bool wide =
417-
(v >= 0x4E00 && v <= 0x9FFF) || // CJK Unified Ideographs
418-
(v >= 0x3400 && v <= 0x4DBF) || // CJK Ext A
419-
(v >= 0x3000 && v <= 0x303F) || // CJK Symbols & Punctuation
420-
(v >= 0x3040 && v <= 0x309F) || // Hiragana
421-
(v >= 0x30A0 && v <= 0x30FF) || // Katakana
422-
(v >= 0xAC00 && v <= 0xD7AF) || // Hangul Syllables
423-
(v >= 0xF900 && v <= 0xFAFF) || // CJK Compatibility Ideographs
424-
(v >= 0xFF01 && v <= 0xFF60) || // Fullwidth ASCII variants
425-
(v >= 0xFFE0 && v <= 0xFFE6) || // Fullwidth symbols
426-
(v >= 0x1F300 && v <= 0x1FAFF); // Emoji & Symbols (approx)
427-
w += wide ? 2 : 1;
410+
w += IsWideCharacter(rune.Value) ? 2 : 1;
428411
}
429412

430413
return w;
431414
}
432415

416+
/// <summary>
417+
/// 判断字符是否为宽字符(在终端中占用两个字符宽度)
418+
/// Determines if a character is wide (occupies two character widths in terminal)
419+
/// </summary>
420+
/// <param name="codePoint">Unicode 码点 / Unicode code point</param>
421+
/// <returns>是否为宽字符 / Whether the character is wide</returns>
422+
static bool IsWideCharacter(int codePoint)
423+
{
424+
// 基于 Unicode 标准的宽字符范围判断
425+
// Based on Unicode standard wide character ranges
426+
return codePoint switch
427+
{
428+
// CJK 统一汉字 / CJK Unified Ideographs
429+
>= 0x4E00 and <= 0x9FFF => true,
430+
// CJK 扩展 A / CJK Extension A
431+
>= 0x3400 and <= 0x4DBF => true,
432+
// CJK 扩展 B-F / CJK Extensions B-F
433+
>= 0x20000 and <= 0x2CEAF => true,
434+
// CJK 扩展 G / CJK Extension G
435+
>= 0x30000 and <= 0x3134F => true,
436+
// CJK 兼容汉字 / CJK Compatibility Ideographs
437+
>= 0xF900 and <= 0xFAFF => true,
438+
// CJK 兼容补充 / CJK Compatibility Supplement
439+
>= 0x2F800 and <= 0x2FA1F => true,
440+
// CJK 符号和标点 / CJK Symbols & Punctuation
441+
>= 0x3000 and <= 0x303F => true,
442+
// 平假名 / Hiragana
443+
>= 0x3040 and <= 0x309F => true,
444+
// 片假名 / Katakana
445+
>= 0x30A0 and <= 0x30FF => true,
446+
// 日文兼容片假名 / Katakana Phonetic Extensions
447+
>= 0x31F0 and <= 0x31FF => true,
448+
// 韩文字母 / Hangul
449+
>= 0xAC00 and <= 0xD7AF => true,
450+
// 韩文兼容字母 / Hangul Jamo
451+
>= 0x1100 and <= 0x11FF => true,
452+
// 全角 ASCII 变体 / Fullwidth ASCII variants
453+
>= 0xFF01 and <= 0xFF60 => true,
454+
// 全角符号 / Fullwidth symbols
455+
>= 0xFFE0 and <= 0xFFE6 => true,
456+
// 箭头符号 / Arrows
457+
>= 0x2190 and <= 0x21FF => true,
458+
// 数学运算符 / Mathematical Operators
459+
>= 0x2200 and <= 0x22FF => true,
460+
// 制表符 / Box Drawing
461+
>= 0x2500 and <= 0x257F => true,
462+
// 方块元素 / Block Elements
463+
>= 0x2580 and <= 0x259F => true,
464+
// 几何图形 / Geometric Shapes
465+
>= 0x25A0 and <= 0x25FF => true,
466+
// 杂项符号 / Miscellaneous Symbols
467+
>= 0x2600 and <= 0x26FF => true,
468+
// 丁贝符 / Dingbats
469+
>= 0x2700 and <= 0x27BF => true,
470+
// 表情符号 / Emoji & Symbols
471+
>= 0x1F000 and <= 0x1FAFF => true,
472+
// 音乐符号 / Musical Symbols
473+
>= 0x1D000 and <= 0x1D24F => true,
474+
// 古代符号 / Ancient Symbols
475+
>= 0x10100 and <= 0x1013F => true,
476+
// 货币符号 / Currency Symbols (部分为宽字符)
477+
>= 0x20A0 and <= 0x20CF => true,
478+
// 字母式符号 / Letterlike Symbols
479+
>= 0x2100 and <= 0x214F => true,
480+
// 数字形式 / Number Forms
481+
>= 0x2150 and <= 0x218F => true,
482+
// 泰文 / Thai (部分为宽字符)
483+
>= 0x0E01 and <= 0x0E7F => true,
484+
// 藏文 / Tibetan
485+
>= 0x0F00 and <= 0x0FFF => true,
486+
// 蒙古文 / Mongolian
487+
>= 0x1800 and <= 0x18AF => true,
488+
// 彝文 / Yi
489+
>= 0xA000 and <= 0xA48F => true,
490+
// 傈僳文 / Lisu
491+
>= 0xA4D0 and <= 0xA4FF => true,
492+
// 预设:窄字符 / Default: narrow character
493+
_ => false
494+
};
495+
}
496+
433497
/// <summary>
434498
/// 格式化属性值用于显示
435499
/// </summary>

0 commit comments

Comments
 (0)