解析具有可变值的数据

时间:2019-06-21 19:15:14

标签: python regex parsing

我在当前项目中遇到一个令人困惑的问题。基本上,我正在逐字节分析MIDI文件(是的,我必须这样做)。 MIDI文件的结构使得轨道中任何给定事件的数据都通过称为“消息”的一系列字节进行传输。 MIDI设备根据状态码知道哪种消息类型,状态码是“消息”中的1-3个字节,具有特定功能的特定ID。

我需要能够浏览MIDI​​文件的数据并将每个“消息”记录为一个独立的对象,以便可以依次放置它们以备后用。我遇到的问题是,当我处理数据时,我需要一种有效的方法来读取每个状态代码,并将其与我编写的处理该类型消息的数据的功能进行匹配。我现在想做的是:

首先,在整个MIDI文件中的任何给定点,我查看接下来的3个字节,并将它们与我所有可能的3字节MIDI状态代码的列表进行比较。这是我的第一个问题。对于所有3个字节的状态码(相当于 6个十六进制数字,这是MIDI编辑中经常使用的编码),第5-8位(也称为第二个十六进制数字)指定当前消息影响的MIDI通道,该通道是可变的且不可预测。由于我无法预测渠道,因此需要将其视为通配符值。换句话说,当我在代码列表中引用它时,我需要以某种方式能够使用6位数字并忽略第二位。我认为我解释得不好,所以这是一个例子:

文件中的6个十六进制代码:Bn7800,其中n是频道号

6位数字代码的列表:['Bn7800','Bn7900','FF2001','FF2F00',...]

我需要在该列表中搜索正确的代码,而忽略第二位数字,因为我无法提前知道它是什么。

我的另一个问题是,一旦有了该代码,就需要调用我编写的处理该特定状态代码的特定函数。我已经将所有函数命名为它们对应的状态代码,但是问题是,我不知道如何获取在上面列表中找到的字符串并使用它来调用函数。例如:

我需要:Bn7800 在列表中,我找到了!因此,我将其存储为名为stat_code = 'Bn7800'的新变量。 但是我不能以这种方式调用我的函数-> self.stat_code(data) 因为stat_code不是我想要的函数的名称。我想要以stat_code命名的函数。

我不确定如何根据存储的变量的值来调用函数。


对不起,如果这令人困惑,我会发现难以完全解释而不尝试解释整个MIDI文件结构。如果有不清楚的地方,请问我问题。谢谢!


编辑:这是一些代码:

self.event_status_codes = {'ff0002': ff_00_02,'ff01': ff_01,'ff02': ff_02,'ff03': ff03,'ff04': ff_04,'ff05': ff_05,'ff06': ff_06,'ff07': ff_07,'ff2001': ff_20_01,'ff2f00': ff_2f_00,'ff5103': ff_51_03,'ff5405': ff_54_05,'ff5804': ff_58_04,'ff5902': ff_59_02,'ff7f': ff_7f,'8n': _8n,'9n': _9n,'an': an,'bn': bn,'cn': cn,'dn': dn,'en': en,'bn7800': bn_78_00,'bn7900': bn_79_00,'bn7a': bn_7a,'bn7b00': bn_7b_00,'bn7c00': bn_7c_00,'bn7d00': bn7d00,'bn7e': bn_7e,'bn7f00': bn_7f_00,'f0': f0,'f7': f7}

    if track_data[hbc:hbc+3] in self.event_status_codes:  
        status_code = track_data[hbc:hbc+3]
        self.status_code(track_data)

作为参考,track_data是我正在解析的原始十六进制序列,而hbc是一个简单的指针,它一次遍历一个 hex digit 文件。我发布了整个状态码字典,但现在主要关注3位数字,因为它们通常指定频道号。另外,从技术上讲,它是Python字典,因为我不得不为每个对应的函数命名,使其与实际代码略有不同,以使其具有可读性和功能性,因此您可以忽略字典中每个键的值。

1 个答案:

答案 0 :(得分:0)

  

我不确定如何根据存储的变量的值来调用函数。

这可以通过按名称引用功能来实现。在您的问题中,您暗示要在self上调用函数,这使操作更加容易:您可以通过使用getattr()函数来获取包含函数指针的属性,然后调用它:

stat_code = 'B67800'
func = getattr(self, f'function_name_{stat_code}')
value = func()
# do stuff with value

如果您的函数是任何其他模块的一部分,这也适用-只需将示例中的self替换为您要从中调用它的模块的名称即可。

如果您需要调用全局定义的函数(不是模块的一部分),则可能需要索引到locals()globals()

func = globals()[f'function_name_{stat_code}']
value = func()