【问题标题】:Regex for matching a music Chord用于匹配音乐和弦的正则表达式
【发布时间】:2012-06-29 01:18:36
【问题描述】:

我正在尝试编写一个函数来解析音乐和弦的字符串表示。

示例:C 大调和弦 -> Cmaj(这是我要解析的)

为了清楚起见,和弦由三个不同的部分组成:

  • 音符(C、D、E、F、G、A)
  • 那个音符的变记号(#、##、b、bb)
  • 和弦名称

对于那些精通音乐的人,我不考虑斜线和弦(故意)。

下面的功能几乎可以工作了。但是它仍然不适用于以下情况:

  • "C#maj" # 匹配并且应该
  • "C#maj7" # 匹配并且应该
  • "C#maj2" # 匹配且不应该

我想如果我可以将chords 正则表达式部分强制放在正则表达式的末尾,那就成功了。我试过在这个字符串之前和之后都使用$,但是没有用。

有什么想法吗?谢谢。

public static void regex(String chord) {                
    String notes = "^[CDEFGAB]";
    String accidentals = "[#|##|b|bb]";
    String chords = "[maj7|maj|min7|min|sus2]";
    String regex = notes + accidentals + chords; 
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(chord);
    System.out.println("regex is " + regex);
    if (matcher.find()) {
        int i = matcher.start();
        int j = matcher.end();
        System.out.println("i:" + i + " j:" + j);           
    }
    else {
        System.out.println("no match!");
    }
}

【问题讨论】:

  • C#maj2C#maj7 之间的模式是相同的 (C#maj\d),因此区分它们并不是正则表达式的真正工作。我会抓取该模式的所有实例,然后使用更多的字符串模式进行验证。但是,您可以构建一个正则表达式,其中包含所有接受的数字作为文字。
  • 我会制作包含所有可能和弦的静态集合。然后查看是否在 Collections 中找到了字符串表示形式。
  • "...对于那些精通音乐的人,我不考虑斜线和弦..." 只是为了记录:您忽略了 大多数 和弦,而不仅仅是斜线和弦.
  • 是的,你是对的。我的意思是我无意为斜线和弦添加匹配,这意味着我必须更改正则表达式结构本身。我打算为chords 字符串添加更多和弦。为了清楚起见,我没有这样做。
  • 别担心,我刚刚度过了每周一次的迂腐时刻 :) 和弦符号(以及其中的方言)有多种“方言”,您甚至可以或多或少地混合使用方言之间的部分。全世界的音乐家(至少有理论背景)都会理解任何组合,但几乎不可能想出一个简单的计算机匹配算法来做到这一点。 (我去过那里;))

标签: regex music-notation


【解决方案1】:

我没有足够的声望来评论 Amit 的帖子。

这是我用来做这个的。重要的是在“m”之前检查“maj”和“min”,否则像 C#m 这样的和弦会出现错误匹配。从技术上讲,这将允许像 C#9000 这样的和弦,但我猜这在你的情况下不会有太大问题。

[A-G](b|#)?(maj|min|m|M|\+|-|dim|aug)?[0-9]*(sus)?[0-9]*(\/[A-G](b|#)?)?

【讨论】:

    【解决方案2】:

    基于 Wiseguy 的回答,我改进了您的正则表达式匹配。我不得不在变量accidentals 之外添加#,因为\b 抛出匹配# 关闭。

    奖励:它甚至可以匹配 Dsus9、D7 等和弦。

    请原谅 JavaScript,但这是我最终使用的代码:

    var notes = "[CDEFGAB]",
      accidentals = "(b|bb)?",
      chords = "(m|maj7|maj|min7|min|sus)?",
      suspends = "(1|2|3|4|5|6|7|8|9)?",
      sharp = "(#)?",
      regex = new RegExp("\\b" + notes + accidentals + chords + suspends + "\\b" + sharp, "g");
    
    var matched_chords = "A# is a chord, Bb is a chord. But H isn't".match(regex);
    
    console.log(matched_chords);

    【讨论】:

      【解决方案3】:

      请原谅 JavaScript,但就纯粹的 REGEX 而言,这种模式似乎有效。您没有规定在哪个和弦名称之后允许哪些数字,但我假设 2 只允许在“sus”之后,7 只允许在“min”和“maj”之后。

      var chords = "C#maj7 C##maj Bbmaj7 Abmin2 Cbmin Dsus";
      var valid_chords = chords.match(/\b[CDEFGAB](?:#{1,2}|b{1,2})?(?:maj7?|min7?|sus2?)\b/g);
      

      【讨论】:

        【解决方案4】:

        在以下几行中将 [] 更改为 ()

        String accidentals = "(#|##|b|bb)";
        String chords = "(maj7|maj|min7|min|sus2)";
        

        否则你只是在创建字符类,所以[maj7|maj|min7|min|sus2] 只是匹配字母m

        我猜你也想添加一个结尾锚$?我看到您之前遇到过问题,但这可能是因为上述问题。


        另外,您是否希望 (#|##|b|bb) 是可选的(即,?(#|##|b|bb)?)?

        【讨论】:

          猜你喜欢
          • 2012-06-29
          • 1970-01-01
          • 1970-01-01
          • 2013-07-03
          • 2014-01-11
          • 2010-10-10
          • 2019-09-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多