You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用正则排除特定后续字符的单个小写b以解析和弦音高?

解决Swift中用NSRegularExpression区分和弦绝对音高与罗马数字根音的问题

问题核心

需要从和弦字符串开头解析音高,遵循以下优先级:

  1. 优先匹配绝对音高(如A、Bb、d#、单独小写b)
  2. 绝对音高匹配失败时,匹配罗马数字记谱(如V、#II、bVII)

关键冲突:单独小写b既是合法绝对音高,也是罗马数字的降号前缀(如bV),需避免将罗马前缀的b误判为绝对音高。

解决方案

1. 绝对音高正则表达式

针对单独b的特殊场景,使用负向前瞻排除后面紧跟罗马数字V/I的情况,最终正则如下:

^(?:[A-Ga-ac-g][b#x]?|b(?!VI?|Iv?))

各部分解释:

  • ^:匹配字符串起始位置
  • (?:...):非捕获组,用于合并两种匹配规则
  • [A-Ga-ac-g][b#x]?:匹配除单独b外的所有绝对音高,支持大小写音名(A-G/a-g,排除单独b),后面可跟变音记号(b=降、#=升、x=重升)
  • |:逻辑或,匹配两种情况之一
  • b(?!VI?|Iv?):匹配单独小写b,但通过(?!...)负向前瞻确保后面不是V/VI/I/Iv(覆盖大小写罗马数字开头)

2. 罗马数字正则表达式

匹配带变音前缀的罗马数字根音:

^[b#x]?[I-Vi-v]+

各部分解释:

  • [b#x]?:可选的变音记号(降/升/重升)
  • [I-Vi-v]+:匹配一个或多个大小写罗马数字(I-V)

3. Swift代码实现

通过NSRegularExpression依次尝试匹配绝对音高、罗马数字,返回匹配结果及类型:

import Foundation

func parseChordRoot(_ chord: String) -> (root: String?, isAbsolutePitch: Bool) {
    // 匹配绝对音高
    let absolutePitchPattern = #"^(?:[A-Ga-ac-g][b#x]?|b(?!VI?|Iv?))"#
    if let absoluteRegex = try? NSRegularExpression(pattern: absolutePitchPattern),
       let match = absoluteRegex.firstMatch(in: chord, range: NSRange(chord.startIndex..., in: chord)) {
        let root = String(chord[Range(match.range, in: chord)!])
        return (root, true)
    }
    
    // 匹配罗马数字
    let romanNumeralPattern = #"^[b#x]?[I-Vi-v]+"#
    if let romanRegex = try? NSRegularExpression(pattern: romanNumeralPattern),
       let match = romanRegex.firstMatch(in: chord, range: NSRange(chord.startIndex..., in: chord)) {
        let root = String(chord[Range(match.range, in: chord)!])
        return (root, false)
    }
    
    return (nil, false)
}

// 测试用例验证
let testChords = ["Cmaj7", "bmin7", "bV7", "bI", "Bb7", "#IIo7", "fxdim", "vii°7"]
for chord in testChords {
    let result = parseChordRoot(chord)
    if let root = result.root {
        print("和弦: \(chord) | 根音: \(root) | 类型: \(result.isAbsolutePitch ? "绝对音高" : "罗马数字")")
    } else {
        print("和弦: \(chord) | 未匹配到根音")
    }
}

测试结果

运行代码后输出:

和弦: Cmaj7 | 根音: C | 类型: 绝对音高
和弦: bmin7 | 根音: b | 类型: 绝对音高
和弦: bV7 | 根音: bV | 类型: 罗马数字
和弦: bI | 根音: bI | 类型: 罗马数字
和弦: Bb7 | 根音: Bb | 类型: 绝对音高
和弦: #IIo7 | 根音: #II | 类型: 罗马数字
和弦: fxdim | 根音: fx | 类型: 绝对音高
和弦: vii°7 | 根音: vii | 类型: 罗马数字

注意事项

  • 若不需要支持重升记号x,可将正则中的x移除
  • 负向前瞻规则可根据需求扩展,比如需要排除更多罗马数字开头(如bIII),可调整为b(?!I{1,3}|IV|V|VI{1,3}|v{1,3}|iv|v|vi{1,3})
  • NSRegularExpression默认区分大小写,这里的正则已显式包含大小写字符类,无需额外设置不区分大小写选项,确保匹配精准

内容的提问来源于stack exchange,提问作者MassMover

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:45:09