在Elixir中解析字节标志位:十六进制字节转标志列表方法
没问题,我来一步步教你怎么把十六进制字节转成对应的标志列表!你已经搞定了十六进制转整数的步骤,剩下的位操作其实很简单,咱们慢慢说~
解决思路和步骤
1. 先定义标志与位位置的映射表
这一步可是核心!因为后续要把标志改成描述性名称时,只需要动这里,完全不用碰逻辑代码。这里要注意:位是从右往左数的,最右边的是第0位,和你给出的例子完全匹配。
比如用Elixir的话可以这么定义(如果你用其他语言,思路完全一致,只是语法稍有不同):
# 后续直接把:flagX改成描述性名称就行,比如:allow_upload, :enable_debug @flag_mappings [ {:flag0, 0}, {:flag1, 1}, {:flag2, 2}, {:flag3, 3}, {:flag4, 4}, {:flag5, 5}, {:flag6, 6}, {:flag7, 7} # 如果是两个完整字节(16位),继续加{:flag8, 8}直到{:flag15, 15}就好 ]
2. 十六进制转整数(你已经掌握啦)
就用你提到的方法把十六进制字符串转成整数:
integer = String.to_integer("0c", 16) # 得到12,对应二进制00001100 integer = String.to_integer("31", 16) # 得到49,对应二进制00110001
3. 用位操作筛选已设置的标志
关键就是用按位与操作来检查每一位是否被设置:
- 对每个标志对应的位位置
bit,计算1 <<< bit(把数字1左移bit位,得到只有该位为1的整数) - 把这个数和我们的目标整数做按位与(
&&&),如果结果不等于0,说明该位是1,对应的标志已被设置
完整的函数示例:
def hex_to_flags(hex_str) do integer = String.to_integer(hex_str, 16) @flag_mappings # 筛选出位被设置的标志项 |> Enum.filter(fn {_flag_name, bit_position} -> (integer &&& (1 <<< bit_position)) != 0 end) # 只提取标志名称 |> Enum.map(fn {flag_name, _bit_position} -> flag_name end) end
测试你的例子
- 调用
hex_to_flags("0c")会返回[:flag2, :flag3](顺序不影响,如果你想要从高位到低位排序,可以加个|> Enum.sort_by(fn flag -> ... end)调整) - 调用
hex_to_flags("31")会返回[:flag0, :flag4, :flag5],和你的例子[:flag5, :flag4, :flag0]只是顺序不同,逻辑上完全一致
后续改标志名称的小技巧
比如你想把:flag2改成:enable_logging,:flag3改成:allow_edit,只需要修改映射表:
@flag_mappings [ {:flag0, 0}, {:flag1, 1}, {:enable_logging, 2}, {:allow_edit, 3}, {:flag4, 4}, {:flag5, 5}, {:flag6, 6}, {:flag7, 7} ]
这样调用hex_to_flags("0c")就会直接返回[:enable_logging, :allow_edit],完全不用改逻辑代码,非常方便!
内容的提问来源于stack exchange,提问作者user1897983
相关产品推荐
相关产品推荐

