将代码点(或二进制)列表转换为字符串

时间:2017-09-24 02:41:43

标签: elixir

我一直致力于Dave Thomas的Programming in Elixir练习。我遇到了一个写一个函数(由于某种原因称为caesar),它接受一个charlist和一个整数来添加到charlist中的每个元素,如果它超过'z则循环回'a' ',所以你应该可以像

一样调用它

MyList.caesar('ryvke', 13)

它应该返回一个字符串。

我有一个映射列表并执行添加的函数,但它返回一个charlist,我无法弄清楚如何将其转换为字符串:

defmodule MyList do
  def caesar(list, n) do
    Enum.map list, &(perform_addition(&1, n))
    |> to_charlist
    |> to_string
  end

  defp perform_addition(char_val, n) when char_val < 122 do
    char_val + n
  end

  defp perform_addition(_, n) do
    97 + n
  end
end

我试过了:

基于最后一个子弹的尝试导致:

MyList.caesar('ryvke', 13)
# => <<127, 194, 134, 194, 131, 120, 114>>

3 个答案:

答案 0 :(得分:19)

要回答标题中的问题:您正在寻找List.to_string/1

iex(1)> List.to_string([97, 98, 99])
"abc"

您没有为这些参数获取可读字符串的原因是您旋转值的逻辑不正确。以下是如何移动小写字母并将其旋转回a,如果它超过z而不接触非小写字母:

# ?a == 97, ?z == 122
defp add(ch, n) when ch in ?a..?z do
  rem((ch - ?a + n), 26) + ?a
end
defp add(ch, n) when ch in ?A..?Z do
  rem(ch - ?A + shift, 26) + ?A
end
defp add(ch, _), do: ch

有了这个,你只需要在输入charlist上映射函数,然后调用List.to_string/1

def caesar(list, n) do
  list |> Enum.map(&add(&1, n)) |> List.to_string
end
iex(1)> MyList.caesar('ryvke', 13)
"elixr"
  

(出于某种原因称为凯撒)

此算法称为Caesar Cipher

答案 1 :(得分:0)

书中所述的问题是:

  

Elixir单引号字符串实际上是单个列表   字符代码。编写一个caesar(list,n)函数,将每个函数加n   列表元素,如果加法导致一个更大的字符,则包装   比z。

上面的答案几乎可以肯定是您在“现实生活”中的处理方式,但是 本书中的练习的重点是通过递归进行操作,因为它在递归一章中。

defmodule MyList do
  def caesar([], _n), do: []

  def caesar([head | tail], n) when head + n > ?z do
    [head + n - ?z + (?a - 1) | caesar(tail, n)]
  end

  def caesar([head | tail], n) do
    [head + n | caesar(tail, n)]
  end
end

这会遍历列表,并使用模式匹配将13个字符ord值添加到小写的ASCII区域中,或将其回绕。

诚然,关于“换行”的含义(例如换行为0或什么?)的问题尚不清楚,因此您必须先知道预期的答案是什么,然后才能确切知道要做什么。 (如果换为0,则以^E作为第一个字符结束,这是一个很大的提示。)

答案 2 :(得分:0)

从算法返回的某些char值超出了可打印字符的范围,这是因为您使用UTF8编码的二进制文件而不是charlist获得了位串。

我的解决方案仅在char的代码点超过?z代码点时考虑减法,或者在char的代码点低于?z代码点值时进行加法。

defmodule Caesar do
  def decoder(list \\ [], plus \\ 13)
  def decoder([], _plus), do: ''
  def decoder([head | tail], plus) when head + plus > ?z do
    [ head - plus | decoder(tail, plus)]
  end
  def decoder([head | tail], plus) when head + plus < ?z do
    [ head + plus | decoder(tail, plus)]
  end
end