Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Elixir中的字节解析标志_Elixir_Mask_Flags - Fatal编程技术网

从Elixir中的字节解析标志

从Elixir中的字节解析标志,elixir,mask,flags,Elixir,Mask,Flags,我有两个十六进制格式的字节,比如“0c”或“31”。 如何将其映射到某些标志值?我想要一个已设置的所有标志的列表 例如: "0c" -> 0000 1100 -> [:flag3, :flag2] "31" -> 0011 0001 -> [:flag5, :flag4, :flag0] 在这里,每个标志都是根据其位置命名的,但稍后我想用更具描述性的名称来命名标志 从十六进制中获取数据很容易,只需字符串。要获取整数(“0c”,16),但之后我迷失在按位的世界中。实际上,

我有两个十六进制格式的字节,比如“0c”或“31”。 如何将其映射到某些标志值?我想要一个已设置的所有标志的列表

例如:

"0c" -> 0000 1100 -> [:flag3, :flag2]
"31" -> 0011 0001 -> [:flag5, :flag4, :flag0]
在这里,每个标志都是根据其位置命名的,但稍后我想用更具描述性的名称来命名标志

从十六进制中获取数据很容易,只需
字符串。要获取整数(“0c”,16)
,但之后我迷失在
按位
的世界中。实际上,通过字符串操作可以避免“按位
的世界”:

"0c"
|> String.to_integer(16) # 12
|> Integer.to_string(2) # "1100"
|> String.codepoints # ["1", "1", "0", "0"]
|> Enum.reverse # ["0", "0", "1", "1"]
|> Enum.with_index # [{"0", 0}, {"0", 1}, {"1", 2}, {"1", 3}]
|> Enum.reduce([], fn
    {"1", index}, acc -> [:"flag#{index}" | acc]
    _, acc -> acc
  end) # [:flag3, :flag2]
否则,可以按如下方式计算:

defmodule FlagBuilder do
  use Bitwise

  def build_flags(number, index \\ 0)
  def build_flags(0, _) do
    []
  end
  def build_flags(number, index) do
    next = fn -> build_flags(number >>> 1, index + 1) end

    case number &&& 1 do
      0 -> next.()
      1 -> [:"flag#{index}" | next.()]
    end
  end
end

a = "31"
|> String.to_integer(16) # 12
|> FlagBuilder.build_flags

如果最后一位是
1
,则要找出最后一位(使用
&&&1
),并构建一个标志。在下一次迭代中给出的数字是在该位上向右移动的输入数字(通过使用
>>1

@Igor为任意大小的输入提供了两个很好的解决方案,但如果您只有1个字节或固定数量的字节,则可以在一行中完成(这里我假设输入为1字节/8位;只需将
n
更改为您想要检查的位数(如果有更多):

fori>>i&&1)==1,do::“flag{i}”
iex(1)>按位使用
按位
iex(2)>n=“31”|>String.to_整数(16)
49
iex(3)>对于i>>i&&1)==1,do::“flag{i}”
[:flag0,:flag4,:flag5]
iex(4)>n=“0c”|>String.to_整数(16)
12
iex(5)>对于i>>i&&1)==1,do::“flag{i}”
[:flag2,:flag3]

对于从0到7的每个数字,我们检查该位是否设置为整数,如果是,则将其转换为原子并收集它。

我将使用二进制模式匹配:

级别“轻松”。只是模式匹配

=
#⇒“\f”
{i1,i2,i3,i4,i5,i6,i7,i8}
#⇒ {0, 0, 0, 0, 1, 1, 0, 0}
是的,我们已经把所有的标志(为了简短起见,上面命名为
i
)从框中映射出来

要将它们转换为
:flagN
原子列表:

[i1、i2、i3、i4、i5、i6、i7、i8]
|>Enum.reverse()
|>带有_索引()的枚举
|>枚举减少([],fn
{0,},acc->acc
{{{},idx},acc->[:“标志{idx}”| acc]
(完)
[:flag3,:flag2]

“中级”一级。创建一个函数,该函数接受
字符串
,并生成元组

def标志(输入)do
#可能一些输入检查会快速失败
=
{i1,i2,i3,i4,i5,i6,i7,i8}
结束

“高级”级别。生成一个宏,该宏将为任意长度的输入生成函数(或直接在模块主体中生成函数)

defmodule标志不起作用
每个枚举(1..10,fn i->
#在此处为长度为1–10的'String'生成一个函数
(完)
结束

奖金轨道。正在导出
flag0
<代码>标记7
当前上下文的变量绕过:

defmodule标志不起作用
defmacro标志(输入)do
制图员=
{:, [],
0..7
|>map(&{::,[],[{:var!,[context:Elixir,import:Kernel],
[{:“旗子{&1},[],长生不老药},1]})
|>Enum.reverse()
}
引述
unquote(映射器)=
结束
结束
结束
defmodule Flags.Test do
导入标志
def测试do
旗帜(“0c”)
[flag0,flag1,flag2,flag3,flag4,flag5,flag6,flag7]
|>带有_索引()的枚举
|>枚举减少([],fn
{0,},acc->acc
{{{},idx},acc->[:“标志{idx}”| acc]
(完)
|>IO.检查(标签:“结果”)
IO.检查(flag2,标签:“flag2”)
结束
结束
标记。测试。测试
#⇒结果:[:flag3,:flag2]
#第2组:1

在后一个例子中,调用
flags(“0c”)

将这些元组转换为原子列表将需要更多的代码。@Dogbert我用转换为原子列表的方法更新了一个答案,但事实并非如此“更多的代码”顺便说一句,它比按位IMHO.Wow更清晰——三个强有力的答案回答了你的问题。
for i <- 0..7, (n >>> i &&& 1) == 1, do: :"flag#{i}"
iex(1)> use Bitwise
Bitwise
iex(2)> n = "31" |> String.to_integer(16)
49
iex(3)> for i <- 0..7, (n >>> i &&& 1) == 1, do: :"flag#{i}"
[:flag0, :flag4, :flag5]
iex(4)> n = "0c" |> String.to_integer(16)
12
iex(5)> for i <- 0..7, (n >>> i &&& 1) == 1, do: :"flag#{i}"
[:flag2, :flag3]