【问题标题】:NSRegularExpression not matching number sign (#)NSRegularExpression 不匹配数字符号 (#)
【发布时间】:2017-08-17 15:25:52
【问题描述】:

我正在开发吉他和弦转置器,因此我想从给定的文本文件中识别吉他和弦。例如G#、Ab、F#m 等

我快到了!由于数字符号(哈希标签),我已经遇到了一些问题。

#

例如,您不能在正则表达式模式中包含数字符号。 NSRegularExpression 不会这样初始化:

let fail:    String = "\\b[ABCDEFG](b|#)?\\b"
let success: String = "\\b[CDEFGAB](b|\\u0023)?\\b"

我必须专门提供 unicode 字符。我可以忍受。

但是,现在我有一个 NSRegularExpression 对象,当我有一行文本时,它不会匹配这些(锐器 = 数字符号):

Am Bb G# C Dm F E

当它开始处理 G# 时,与第二个捕获组关联的锐利不匹配。 (即 NSTextCheckingResult 的第二个范围的位置为 NSNotFound)注意,它适用于 Bb...它匹配 'b'

我想知道我需要在这里做什么。似乎文档没有涵盖“#”的这种情况,实际上有时在正则表达式模式中使用它(我认为与 cmets 或某事有关)

最好的一点是不必查找# 的unicode 标识符,而只需将其用作字符串“#”,然后将其转换为与模式很好地配合。有可能 \u0023 实际上不是与 # ... 关联的代码

【问题讨论】:

  • 数字符号和尖号不一样吗?
  • 让我准确地说:你不想匹配EdddF#7 呢?根本原因很清楚,但解决方案需要针对这种特定类型的输入进行定制。并尝试"\\b[CDEFGAB][bm\\u0023]?(?!\\w)"。或\\b[CDEFGAB][bm\\u0023]?+(?!\\w)。不确定什么最适合这里。请检查。
  • 请检查我上面的 2 个解决方案,让知道哪一个效果最好。
  • @SumnerEvans 我的代码最终将支持两者,但我在这里是面向用户的。大多数人写 'b' 表示平号(键盘上没有平号!),#(数字符号)表示尖号(还有一个尖号)
  • @WiktorStribiżew 请不要想太多。为简洁起见,我缩短了代码。我有另一个处理和弦结构的捕获组,效果很好。问题是关于匹配 # 符号。现在,我只是让这个例子简洁。现在我在乎这张纸条。

标签: ios regex swift unicode nsregularexpression


【解决方案1】:

\b word boundary 是一个依赖于上下文的构造。它在 4 种上下文中匹配:1) 在字符串开头和单词 char 之间,2) 在单词 char 和字符串结尾之间,3) 在单词和非单词之间,以及 4) 非单词和单词 char。

您的正则表达式的编写方式最终使正则表达式引擎在# 之后看到\b,这意味着# 仅在其后有单词char 时才会匹配。

如果您将\b 替换为(?!\w),如果当前位置右侧有一个单词char,则否定前瞻将导致匹配失败。

所以,你可以使用

\\b[CDEFGAB](b|\\u0023)?(?!\\w)

请参阅regex demo

详情

  • \b - 单词边界
  • [CDEFGAB] - 集合中的一个字符
  • (b|\\u0023)? - b# 的可选序列
  • (?!\\w) - 如果在右侧有一个单词 char,则匹配失败(并导致回溯到前面的模式!为避免这种情况,请在 ? 之后添加 + 以防止回溯到该模式)当前位置。

【讨论】:

  • 看起来不错。我对正则表达式还是很陌生。所以最后一块拼图是,我可以有一个G# 的和弦,但我也可以有一个G#m7 的和弦有很多风格的和弦,例如,我目前失败的正则表达式模式是:"\\b[CDEFGAB](\\u0023|b|♯|♭)?(7\\(\\[\\u0023\\]5,b9\\)|maj13\\[\\u0023\\]11|7\\(b5,b9\\)|7\\(\\[\\u0023\\]5,\\[\\u0023\\]9\\)|7\\(b5,\\[\\u0023\\]9\\)|sus2sus4|maj9\\[\\u0023\\]11|m6add9|maj7b5|maj7\\[\\u0023\\]5)?\\b"(由于评论限制,我遗漏了一堆,但你明白了)
  • 我还应该指出,它匹配Ab,但不匹配G# 鉴于我的语法,这有什么意义?
  • 我得到了一些不同变化的不同结果。请不要使用音乐术语,它们没有帮助。你有 AbG# ,我看到了 the regex matches them。它在所有情况下都有效吗?我刚刚用?+(?!\\w) 替换了?\\b。只要给我一个字符串,告诉我什么应该匹配,什么不应该匹配。
  • A B C# Db G#m A#7 将是一个好的开始。请认识到 # 或 b 之后的任何内容都可能来自 50 个和弦列表,因此我需要以参数方式构建我的模式。
  • 喜欢this?抱歉,您的问题现在变得太模糊了。
【解决方案2】:

(我想首先说@WiktorStribiżew 提供了巨大的帮助,如果没有他,我现在写的东西是不可能的!我不关心 StackOverflow 积分和代表,所以如果你喜欢这个答案,请点赞他的答案。)

这个问题发生了很多次,并且出现了一些问题。 这个问题最终应该被称为 如何在 iOS 上使用 Regex 来检测文本文件中的音乐和弦?

答案是(到目前为止),而不是简单的。

音乐理论速成课程

在音乐中你有音符。它们由A->G 之间的一个字母和一个称为accidental 的可选符号组成。 (音符与播放该音符时您听到的声音的声学频率有关)变音记号可以是flat(表示为 或简单的b),或sharp(表示为 或简称为#,因为这些更容易在键盘上键入)。变音记号用于使音符高半音 (#) 或低半音 (b)。因此,F# 与 Gb 具有相同的声学频率。在钢琴上,白键是没有变记号的音符,黑键代表有变记号的音符。根据乐曲的某些因素,该乐曲不会混合意外类型。它要么是整个作品的平坦部分,要么是尖锐的。 (取决于乐曲的音调,但这在这里无关紧要。)

就正则表达式而言,您有类似 ABCDEFG 的东西吗?来确定注释。实际上它更复杂。

然后,音乐和弦由根音和和弦类型组成。和弦有50多种。他们有一个独特的“文本签名”。此外,“主要”和弦的签名为空。所以就伪正则表达式而言,你有一个和弦:

[ABCDEFG](b|#)?(...|...|...)?

您识别为音符的第一部分(如前所述),最后一个可选部分是确定和弦类型。省略了不同的类型,但可以像m(用于小和弦)或maj7#5(用于带有增五度的大七和弦......别担心。只要知道有许多字符串常量来表示一个和弦类型)

最后,对于吉他,您通常会有一个相应的低音音符,它会在一定程度上改变和弦的音调。您可以通过添加斜线和注释来表示这一点,给出一般的伪形式:

[ABCDEFG](b|#)?(...|...|...)?(/[ABCDEFG](b|#)?)? // NOT real Regex
real examples: C/F or C#m/G# and so on

最后一部分有一个斜线,然后是相同的模式来识别一个音符。

因此,将所有这些放在一起,通常我们希望找到可以采用多种形式的和弦,例如:

F Gm C#maj7/G# F/C Am A7 A7/F# Bmaj13#11

我希望找到一个正则表达式来统治它们。我最终编写了有效的代码,尽管我似乎有点想得到我想要的结果。

你可以see this code here,用 Swift 编写。就我的目的而言,它并不完整,但它会解析一个字符串,返回一个和弦结果列表及其在原始字符串中的文本范围。您必须从那里完成实施以满足您的需求。

在 iOS 上存在一些问题:

  • iOS 根本无法很好地处理数字符号 (#)。在提供正则表达式模式或匹配文本时,我要么必须将 # 替换为其 unicode \u0023,要么最终将所有出现的 # 替换为另一个字符(例如“S”),然后在正则表达式完成后将其转换回来这是事情。所以我写的这段代码经常在做任何事情之前必须“清理”模式或输入文本。

  • 我无法获得正则表达式模式来完美解析和弦结构。它不适用于带有低音音符的和弦,但它可以成功地匹配带​​有低音音符的和弦,然后我必须拆分这两个组件并分别解析它们,然后重新组合它们

  • Regex 确实有点像巫术,我认为对于很多人来说如此困惑的东西,它还有不同的依赖于平台的实现,这很糟糕。例如,Wiktor 向我推荐了他写的 Regex 模式,以帮助我解决 www.regex101.com 上的问题,该模式可以在该网站上运行,但这些在 iOS 上不起作用,并且 NSRegularExpression 会抛出错误(通常它有一些东西与这个 # 字符有关)

  • 我的解决方案完全不考虑性能。它只是想让它工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-15
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 2013-11-09
    • 2015-10-08
    • 1970-01-01
    相关资源
    最近更新 更多