将<…>作为“foo bar<hello world>等”中的一项的正则表达式(目标:简单音乐/lilypond解析)

2024-05-26 07:46:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Python(3)中使用re模块,并希望替换(re.sub公司(regex,replace,string))以下格式的字符串

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

^{pr2}$

甚至是

^{3}$

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

帮忙会很好的!在

第1页

整个故事是一个音乐故事: 我有Lilypond格式的字符串(或者更好,是非常简单的核心格式的一个子集,只有注释和持续时间),并希望将它们转换为python pairs int(持续时间)和list(音高字符串)。性能并不重要,所以我可以来回转换它们,用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''"]),
]

基本格式是字符串+数字,如:e4bes16

  • 列表项
  • 字符串可以由多个(至少是一个)字符组成
  • 字符串后接零位或多个数字:e bes g4 c16
  • 字符串后面跟零个或多个“或”(未组合):e'bes,f''2g,,4
  • 字符串可以由字符串列表替换,列表限制符是<;>;:4数字在后面>;,不允许有空格

第2页

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


Tags: 字符串答案ltgtre列表foo音乐
2条回答

我知道您不是在寻找通用解析器,但是pyparsing使这个过程非常简单。您的格式看起来非常类似于我作为最早pyparsing示例之一编写的chemical formula parser。在

以下是使用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)

有了这个输出:

^{pr2}$

你的第一个问题可以这样回答:

>>> import re
>>> t = "foo <bar e word> f ga <foo b>"
>>> t2 = re.sub(r"(^|\s+)(?![^<>]*?>)", " #", t).lstrip()
>>> t2
'#foo #<bar e word> #f #ga #<foo b>'

我添加了lstrip()以删除此模式结果之前出现的单个空格。如果您想使用第一个选项,只需将#<替换为<。在

您的第二个问题可以用下面的方式解决,尽管您可能需要考虑一个列表中的,,比如['g,', "b'"]。字符串中的逗号是否应该在那里?也许有更快的方法。以下只是概念的证明。列表理解可能会取代最后一个元素,尽管这会非常复杂。在

^{pr2}$

相关问题 更多 >