Reputation: 293
I am a newbie to Haskell and am trying to cipher the plain text by using shifting
the ASCII values and if my plain text contains a number,then it has to encode each digit by putting a special symbol in place of the digit like (0=*,1=',2=~,3=!,4=@,5=#,6=$, 7=%,8=^,9=&)
. so here is my code for encryption
import Data.Char
canEncrypt :: Char -> Bool
canEncrypt c = isLower(c) && isAscii(c)
encryptChar :: Char -> Char -> Char
encryptChar shift c
| canEncrypt c = chr(ord(c)+ord(shift))
| isUpper c = c
| isNumber c = if (c == 0) then '*'
else if (c == 1) then '\'
else if (c == 2) then '~'
else if (c == 3) then '!'
else if (c == 4) then '@'
else if (c==5) then '#'
else if (c==6) then '$'
else if (c==7) then '%'
else if (c==8) then '^'
else '&'
and yeah it's a little spaghetti code but when I compiling it it showing an error like below
|
| lexical error in string/character literal at character ' '
21 | isNumber c = blah blah blah..
|
I think am doing something terribly wrong here that I don't know what.so don't hesitate for such silly question am a just beginner so any help would be appreciated and also is there any other implementation to implement this kind of if-else
problem?
Thank you
Upvotes: 2
Views: 1651
Reputation: 71495
Here's your problem:
if (c == 1) then '\'
The backslash is a special character in string and character literals; it's used to escape the following character, so that you can use other special characters inside string and character literals.
So '\'
is read by the Haskell parser as a single quote beginning a character literal, followed by a backslash-escaped single quote inside the character literal, but then there's no unescaped single quote to properly end the character literal, which is why it complains that the next character is a "lexical error in string/character literal".
If you're trying to write a character literal for the backslash character, then you need to use a backslash to escape the backslash to have Haskell read it as a backslash in a character literal, rather than a backslash modifying the interpretation of the next character. So: '\\'
If you're trying to write a character literal for a single quote character, then you had the backslash-escaped single quote character correct for the quote inside the character literal, but you still need to add a non-escaped quote to terminate the character literal. So: '\''
Upvotes: 5
Reputation: 476709
You write:
else if (c == 1) then '\'
Based on your question, you want to return a quote ('
). You do this by escaping the quote, but you need an end of char marker. So we should write '\''
else if (c == 1) then '\''
That being said, this is a nice cascade of if
-then
-else
s.
Since c
is a Char
, you can not perform a c == 1
, since the equivalence function (==) :: Eq a => a -> a -> Bool
thus compares two a
s (so the same type). So we need to write it like:
else if (c == '1') then '\''
Now we have a long cascade of if
-then
-else
s. This is not very elegant, and hard to understand. We can use pattern matching for this:
encryptChar :: Char -> Char -> Char
encryptChar shift c
| canEncrypt c = chr (ord c + ord shift)
| isUpper c = c
encryptChar _ '0' = '*'
encryptChar _ '1' = '\''
encryptChar _ '2' = '~'
encryptChar _ '3' = '!'
encryptChar _ '4' = '@'
encryptChar _ '5' = '#'
encryptChar _ '6' = '$'
encryptChar _ '7' = '%'
encryptChar _ '8' = '^'
encryptChar _ '9' = '&'
We can also define a list of values, a list of Char
s is a String
:
digittrans = "*'~!@#$%^&"
and then we can lookup the i-th index with: digittrans !! i
. So by parsing a string "4" to the Int
counterpart with read "4"
, we can obtain the correct value:
encryptChar :: Char -> Char -> Char
encryptChar shift c
| canEncrypt c = chr (ord c + ord shift)
| isUpper c = c
| isDigit c = digittrans !! read [c]
where digittrans = "*'~!@#$%^&"
We also need to think of a resultion mechanism in case all the above checks fail (something is not encryptable, nor uppercase, nor a digit). In that case we can for instance decide to return the character itself:
encryptChar :: Char -> Char -> Char
encryptChar shift c
| canEncrypt c = chr (ord c + ord shift)
| isUpper c = c
| isDigit c = digittrans !! read [c]
where digittrans = "*'~!@#$%^&"
encryptChar _ c = c
Upvotes: 7