【问题标题】:Convert list of codepoints (or binary) to string将代码点(或二进制)列表转换为字符串
【发布时间】:2018-03-05 07:02:24
【问题描述】:

我一直在练习 Dave Thomas 的 Programming in Elixir 的练习。我遇到了一个说要编写一个函数(由于某种原因称为caesar),它需要一个字符列表和一个整数来添加到字符列表中的每个元素,如果它超过'z',则循环回到'a',所以你应该可以这样称呼它

MyList.caesar('ryvke', 13)

它应该返回一个字符串。

我有一个映射列表并执行加法的函数,但它返回一个字符列表,我不知道如何将其转换为字符串:

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>>

【问题讨论】:

    标签: elixir


    【解决方案1】:

    您的算法返回的一些 char 值超出了可打印字符的范围,这就是原因,因为您得到的是 UTF8 编码的二进制文件而不是 charlist。

    我的解决方案仅在 char 的代码点超过 ?z 代码点时考虑减法,或在低于 ?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
    

    【讨论】:

      【解决方案2】:

      书中所说的问题是:

      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 添加到字符或值,或将其环绕在小写 ASCII 区域内。

      诚然,对于“换行”的含义(例如换行到 0 还是什么?),这个问题并不清楚,因此您必须先凭直觉知道预期的答案是什么,然后才能确切知道该做什么。 (如果你换成 0,你会发现 ^E 是第一个字符,这是一个很大的提示。)

      【讨论】:

        【解决方案3】:

        回答标题中的问题:你在找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
        

        有了这个,你只需要将函数映射到输入字符列表,然后调用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

        【讨论】:

          猜你喜欢
          • 2016-07-16
          • 2020-06-20
          • 2019-08-13
          • 2012-10-05
          • 2021-10-12
          • 2021-02-24
          • 1970-01-01
          相关资源
          最近更新 更多