Python和弦字典含#、/特殊字符的正则匹配问题修复与优化
问题修复与代码优化方案
问题根源分析
- 单词边界
\b失效:\b仅匹配单词字符(字母/数字/下划线)与非单词字符的边界,#属于非单词字符,导致C#被拆分为C(匹配triadeMaj)和#(被误处理)。 - 斜线和弦未整体匹配:原正则未考虑转位和弦(如
D/F#)的结构,将其拆分为前后两部分分别匹配,导致错误拆分。 - 匹配顺序不合理:未按和弦长度排序,短和弦会优先匹配长和弦的前缀(如先匹配
C再匹配Cmaj7,导致Cmaj7被拆分)。 - 代码冗余:每个和弦类型单独创建
DataFrame,重复代码过多。
优化后的实现代码
import pandas as pd # 1. 重构和弦数据:用字典统一管理所有和弦类型与对应和弦列表 chord_types = { 'triadeMaj': ['C','C#','Db','D','D#','Eb','E','F','F#','Gb','G','G#','Ab','A','A#','Bb','B'], 'triadeMen': ['Cm','C#m','Dbm','Dm','D#m','Ebm','Em','Fm','F#m','Gbm','Gm','G#m','Abm','Am','A#m','Bbm','Bm'], 'triadeDim': ['Cdim','C#dim','Dbdim', 'Ddim', 'D#dim', 'Ebdim', 'Edim', 'Fdim', 'F#dim', 'Gbdim','Gdim', 'G#dim', 'Abdim', 'Adim', 'A#dim', 'Bbdim', 'Bdim'], 'triadeAug': ['Caug','C#aug','Dbaug','Daug','D#aug','Ebaug','Eaug','Faug','F#aug','Gbaug','Gaug','G#aug','Abaug','Aaug','A#aug','Bbaug','Baug'], 'setima': ['C7','C#7','Db7','D7','D#7','Eb7','E7','F7','F#7','Gb7','G7','G#7','Ab7','A7','A#7','Bb7','B7'], 'setimaMen': ['Cm7','C#m7','Dbm7','Dm7','D#m7','Ebm7','Em7','Fm7','F#m7','Gbm7','Gm7','G#m7','Abm7','Am7','A#m7','Bbm7','Bm7'], 'setimaMaj': ['Cmaj7', 'C#maj7', 'Dbmaj7', 'Dmaj7', 'D#maj7', 'Ebmaj7', 'Emaj7', 'Fmaj7', 'F#maj7','Gbmaj7','Gmaj7', 'G#maj7','Abmaj7','Amaj7','A#maj7','Bbmaj7','Bmaj7'], 'setimaMenQui': ['Cm7b5','C#m7b5', 'Dbm7b5', 'Dm7b5', 'D#m7b5', 'Ebm7b5','Em7b5', 'Fm7b5', 'F#m7b5', 'Gbm7b5', 'Gm7b5', 'G#m7b5', 'Abm7b5', 'Am7b5', 'A#m7b5', 'Bbm7b5', 'Bm7b5'], 'sexta': ['C6','C#6','Db6','D6','D#6','Eb6','E6','F6','F#6','Gb6','G6','G#6','Ab6','A6','A#6','Bb6','B6'], 'sextaMen': ['Cm6','C#m6','Dbm6','Dm6','D#m6','Ebm6','Em6','Fm6','F#m6','Gbm6','Gm6','G#m6','Abm6','Am6','A#m6', 'Bbm6','Bm6'] } # 2. 生成正则替换规则 replace_rules = {} for type_name, chords in chord_types.items(): # 按和弦长度降序排序,优先匹配长和弦(避免短和弦截断长和弦) sorted_chords = sorted(chords, key=lambda x: -len(x)) # 用(?<!\S)/(?!\S)代替\b,兼容特殊字符;(?:/\S+)?支持匹配转位和弦的斜线部分 pattern = fr"(?<!\S)({'|'.join(sorted_chords)})(?:/\S+)?(?!\S)" replace_rules[pattern] = type_name # 3. 添加未匹配项的规则 replace_rules[r"(?<!\S)\S+(?!\S)"] = 'outros' # 4. 应用替换(假设df是你的原始数据框) df['chordType'] = df['chords'].replace(replace_rules, regex=True)
关键优化点说明
- 统一数据结构:用字典替代多个
DataFrame,大幅减少重复代码,便于后续维护。 - 修复边界匹配:使用
(?<!\S)(前面为空白/开头)和(?!\S)(后面为空白/结尾)替代\b,完美兼容带#的和弦。 - 支持转位和弦:通过
(?:/\S+)?匹配斜线及后续的低音声部,将整个转位和弦视为一个整体匹配。 - 优化匹配顺序:按和弦长度降序排序,确保长和弦(如
Cmaj7)优先匹配,避免被短和弦(如C)截断。
修复后结果示例
| chords | chordType |
|---|---|
| C#, E7, Abm, Amaj7, E, Abm, C#m, E | triadeMaj, setima, triadeMen, setimaMaj, triadeMaj, triadeMen, triadeMen, triadeMaj |
| E, A7, G6, D/F#, F6, E, Em, D7/F#, Fmaj7, E, A7, G6, D7/F#, F6, Em, D, Dm7, E | triadeMaj, setima, sexta, triadeMaj, sexta, triadeMaj, triadeMen, setima, setimaMaj, triadeMaj, setima, sexta, setima, sexta, triadeMen, triadeMaj, setimaMen, triadeMaj |
内容的提问来源于stack exchange,提问作者PM92
相关产品推荐
相关产品推荐

