我一直致力于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>>
答案 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