Skip to main content
 首页 » 编程设计

and so on"中的一项的正则表达式(目标 : Simple music/lilypond parsing)" rel="bookmark">python之将 ...> 作为 "foo bar hello world> and so on"中的一项的正则表达式(目标 : Simple music/lilypond parsing)

2024年08月29日35Leo_wl

我在 Python(3) 中使用 re 模块,并想用以下格式替换 (re.sub(regex, replace, string)) 一个字符串

"foo <bar e word> f ga <foo b>"  

到

"#foo <bar e word> #f #ga <foo b>" 

甚至

"#foo #<bar e word> #f #ga #<foo b>"  

但我无法在 <...> 构造中将单个单词与单词边界隔离开。

帮助会很好!

附言 1

整个故事是一个音乐故事: 我有 Lilypond 格式的字符串(或者更好的是,非常简单的核心格式的一个子集,只有音符和持续时间)并且想将它们转换为 python 对 int(duration),list(of pitch strings)。性能并不重要,所以我可以来回转换它们,用 python 列表迭代,拆分字符串并再次加入它们等等。 但是对于上面的问题我没有找到答案。

源字符串

"c'4 d8 < e' g' >16 fis'4 a,, <g, b'> c''1" 

应该导致

[ 
(4, ["c'"]), 
(8, ["d"]), 
(16, ["e'", "g'"]), 
(4, ["fis'"]), 
(0, ["a,,"]), 
(0, ["g", "b'"]), 
(1, ["c''"]), 
] 

基本格式是 String+Number 像这样:e4 bes16

  • 列表项
  • 字符串可以包含多个,至少一个,[a-zA-Z]个字符
  • 字符串后跟零个或多个数字:e bes g4 c16
  • 字符串后跟零个或多个 ' 或 ,(未合并):e' bes, f'''2 g,,4
  • 字符串可以用字符串列表代替,列表限制符是<>:4 >后面的数字,不允许有空格

附言2

目标不是创建 Lilypond 解析器。它真的只是非常短的片段,没有附加功能,没有插入注释的扩展吗?如果这不起作用,我会选择另一种格式(简化),如 ABC。所以任何与 Lilypond 有关的东西(“通过 lilypond 运行它,让它在 Scheme 中给出音乐数据,解析它”)或其工具链肯定不是这个问题的答案。该软件包甚至还没有安装。

请您参考如下方法:

我知道您不是在寻找通用解析器,而是在寻找 pyparsing使这个过程非常简单。您的格式似乎与 chemical formula parser 非常相似我写的是最早的 pyparsing 示例之一。

这是使用 pyparsing 实现的问题:

from pyparsing import (Suppress,Word,alphas,nums,Combine,Optional,Regex,Group, 
                       OneOrMore) 
 
""" 
List item 
 -the string can consist of multiple, at least one, [a-zA-Z] chars 
 -the string is followed by zero or more digits: e bes g4 c16 
 -the string is followed by zero or more ' or , (not combined):  
  e' bes, f'''2 g,,4 
 -the string can be substituted by a list of strings, list limiters are <>; 
  the number comes behind the >, no space allowed 
""" 
 
LT,GT = map(Suppress,"<>") 
 
integer = Word(nums).setParseAction(lambda t:int(t[0])) 
 
note = Combine(Word(alphas) + Optional(Word(',') | Word("'"))) 
# or equivalent using Regex class 
# note = Regex(r"[a-zA-Z]+('+|,+)?") 
 
# define the list format of one or more notes within '<>'s 
note_list = Group(LT + OneOrMore(note) + GT) 
 
# each item is a note_list or a note, optionally followed by an integer; if 
# no integer is given, default to 0 
item = (note_list | Group(note)) + Optional(integer, default=0) 
 
# reformat the parsed data as a (number, note_or_note_list) tuple 
item.setParseAction(lambda t: (t[1],t[0].asList()) ) 
 
source = "c'4 d8 < e' g' >16 fis'4 a,, <g, b'> c''1" 
print OneOrMore(item).parseString(source) 

有了这个输出:

[(4, ["c'"]), (8, ['d']), (16, ["e'", "g'"]), (4, ["fis'"]), (0, ['a,,']),  
 (0, ['g,', "b'"]), (1, ["c''"])]