将一串数字字符串转换为类似于旧手机的单词

时间:2018-10-24 19:37:21

标签: string list haskell

基本上,我有一个由字符串组成的列表列表,这些字符串仅是数字,例如[“ 22”,“ 333”,“ 2”],我想将其转换为字符串“ bea”。就像旧手机一样,如果您按两次2则得到b,如果按4则得到j,就象旧手机一样。只能使用前奏功能

我这样尝试过

numbers ws [] = ws
numbers ws (x:xs) = if head "2ABC" == head x
                    then ws ++ "2ABC" !! length x ++ numbers ws xs
                    else if head "3DEF" == head x
                    then ws ++ "3DEF" !! length x ++ numbers ws xs
....

但是这给了我错误,所以您可以帮助我吗?

3 个答案:

答案 0 :(得分:6)

一个典型的错误是在一个函数中实现了太多的逻辑。与其尝试将整个解码工作转换成numbers函数,不如将任务拆分为可重用的组件,这样它们就易于理解,调试和重用,可能会更好。

作为第一个功能,我们可以将数字映射到包含字符的String上,例如:

digtoseq :: Char -> String
digtoseq '2' = "abc"
digtoseq '3' = "def"
digtoseq '4' = "ghi"
digtoseq '5' = "jkl"
digtoseq '6' = "mno"
digtoseq '7' = "pqrs"
digtoseq '8' = "tuv"
digtoseq '9' = "wxyz"
digtoseq '0' = " "

我们可以在此处添加其他字符,例如'.',以指定每个电话键后面的顺序。

现在,我们可以实现一个利用digtoseq的函数,例如digstrtoseq

digstrtoseq :: String -> Char
digstrtoseq (x:xs) = digtoseq x !! length xs

在这里,我们采用字符串的长度以及第一个字符,然后遍历字符串digtoseq x,以获得第n-1个元素(使用{{1} }输入字符串的长度)。因此,对于n,我们得到:

"22"

因此,现在只需Prelude> digstrtoseq "22" 'b' Prelude> digstrtoseq "33" 'e' Prelude> digstrtoseq "2" 'a' 在输入字符串上ping此函数即可。

map

然后我们获得:

numbers :: [String] -> String
numbers = map digstrtoseq

请注意,这里我们做了一些假设,其中一些可以通过重写函数来改善,而其他一些则可以通过更改输入的类型来更好地解决:

  1. 我们假设没有字符串的长度大于其后面序列的长度,因此不会出现Prelude> numbers ["22", "33", "2"] "bea"
  2. 我们假设string元素中的字符在整个字符串中重复出现,因此"2222"不会出现;
  3. 我们假设字符串仅包含有效数字,所以没有"231";
  4. 我们假设每个字符串至少包含一个字符,所以没有"~"

大量的假设源自以下事实:我们在这里使用""作为输入类型,这提供了很大的自由度。是的,在这种情况下可能会引发错误或返回[String],但最好定义如下类型:

Nothing

,然后输入data Key = Two | Three | Four | Five | Six | Seven | Eight | Nine | Zero 作为输入,因为假设(2)和(3)可以通过输入类型简单地“保证”。

答案 1 :(得分:2)

威廉击败了我,但这就是我想出的。您可能还是想完成键盘

numToChar :: Char -> Int -> Char
numToChar '2' i = "abc" !! (i - 1)
numToChar '3' i = "def" !! (i - 1)
numToChar '4' i = "ghi" !! (i - 1)
numToChar '5' i = "jkl" !! (i - 1)
numToChar '6' i = "mno" !! (i - 1)
numToChar '7' i = "pqrs" !! (i - 1)
numToChar '8' i = "tuv" !! (i - 1)
numToChar '9' i = "wxyz" !! (i - 1)

numbers n = [numToChar (head x) (length x) | x <- n]

答案 2 :(得分:0)

确实有更直接的翻译或映射方法。 ASCII字符集可用于此目的。此功能很强大。我可以看到的唯一限制是ASCII字符集的长度。假设是我们无法键入将不使用的内容。第一位数字只重要。以后可以使用任何东西。

td=\(s:sx)->[toEnum (47+d+e+(length sx))::Char|d<-[fromEnum s],e<-[2*(mod d 50) + if d > 55 then 1 else 0]]

以任何方式使用td。

concat $ map td ["222","33","9999","4"]

“ cezg”