babalae/better-genshin-impact · warning · FormatException

和弦缺少右括号

Error message

和弦缺少右括号

What it means

Thrown by MusicScoreParser.ParseYuanQinTokens(string) when a chord is opened with '(' but no matching ')' is found in the remaining sheet string. The method uses sheet.IndexOf(')', index + 1) and throws if the result is -1 (no closing parenthesis).

Source

Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:292

    private static List<YuanQinToken> ParseYuanQinTokens(string sheet)
    {
        var tokens = new List<YuanQinToken>();
        var index = 0;
        while (index < sheet.Length)
        {
            if (sheet[index] == '|')
            {
                index++;
                continue;
            }

            string keys;
            if (sheet[index] == '(')
            {
                var end = sheet.IndexOf(')', index + 1);
                if (end < 0)
                {
                    throw new FormatException("和弦缺少右括号");
                }

                keys = sheet[(index + 1)..end];
                index = end + 1;
            }
            else
            {
                keys = sheet[index].ToString();
                index++;
            }

            if (index >= sheet.Length || sheet[index] != '[')
            {
                throw new FormatException($"音符 {keys} 缺少时值");
            }

            var bracketEnd = sheet.IndexOf(']', index + 1);
            if (bracketEnd < 0)

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Find the unclosed '(' in the sheet string and add the matching ')'.
  2. Use a sheet syntax validator that checks bracket/parenthesis balance before parsing.
  3. Check the PerformanceScore.Error property for the position context.
Defensive patterns

Strategy: validation

Validate before calling

// Check parenthesis balance before parsing
int open = sheet.Count(c => c == '(');
int close = sheet.Count(c => c == ')');
if (open != close) { logger.LogError("括号不匹配:{Open} 个 '(' vs {Close} 个 ')'", open, close); }

Try / catch

var score = await parser.ParseAsync(path, rootFolder, ct);
if (!string.IsNullOrEmpty(score.Error)) { logger.LogWarning(score.Error); }

Prevention

When it happens

Trigger: A yuanqin sheet string containing '(' without a subsequent ')'. For example, '(QW[1]' where the closing ')' was omitted.

Common situations: Manual score authoring error; truncated sheet; conversion tool that fails to balance parentheses.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/b5f7a600dc00a7d2. Report an issue: GitHub.