2017-11-21 16 views
2

私はHaskellの初心者で、shiftingのASCII値を使用してプレーンテキストを暗号化しようとしています。プレーンテキストに数字が含まれている場合は、(0=*,1=',2=~,3=!,[email protected],5=#,6=$, 7=%,8=^,9=&)のような数字の代わりに特殊記号を入れてエンコードする必要があります。ので、ここで暗号化文字 ''の文字列/ charcterリテラルの字句エラー?

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

ための私のコードで、ええ、それは少しスパゲッティコードですが、私はそれはのような

| 
    | lexical error in string/character literal at character ' ' 
21 | isNumber c = blah blah blah.. 
    | 

の下にエラーを示すそれをコンパイルするとき、私は私のドンことをここにひどく間違って何かをやっていると思います何も分かりません。そんな愚かな質問に躊躇しないでください。ちょっと初心者なので、どんな助けもありがとうございます。この種の実装には他にも何か問題がありますか? はここにあなたの問題ですあなた

+3

また、エラーを解決するためのヘルプを求めるときは、今後もエラーメッセージを編集したり略したりしないでください。もしあなたが*あなた*に無意味であっても、あなたがあなたを助けようとしている人々があなたを助けることができるという情報が含まれています。例えば、これは、それが不平を言っていた語彙エラーの正確な文字位置を含んでいたでしょう。 – Ben

+3

スタイルコメント: 'if'チェーンの代わりに' case'を使うことができます。 '0 ' - >' * 'のcase c; '1' - > '\\'; ... '。すべてのケースを同じ列にインデントすることができます。複数の定義式を使用することもできます。 – chi

答えて

7

あなたが書く:あなたの質問に基づいて

else if (c == 1) then '\'

を、あなたは引用符(')を返すようにしたいです。これを行うには引用符をエスケープしますが、最後にcharマーカーが必要です。 then - - else Sだから我々は言われていること'\''

else if (c == 1) then '\''

を記述する必要があり、これはifの素敵なカスケードです。 cので

Charある等価関数(==) :: Eq a => a -> a -> Boolは、従って、2つのa S(SO同じタイプ)とを比較するので、あなたは、c == 1を行うことができません。だから私たちは以下のようにそれを記述する必要があります。 - thenからelse

else if (c == '1') then '\''

今、私たちはifの長いカスケードを持っています。これはあまりエレガントではなく、理解しにくいです。我々はまた、値のリストを定義することができますChar SのリストがStringある

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' = '&'

digittrans = "*'[email protected]#$%^&" 

し、我々は私を検索することができます私たちは、このためをマッチングパターンを使用することができます番目のインデックスはdigittrans !! iです。上記のすべてのチェックは(失敗何かが暗号化可能ではありません

encryptChar :: Char -> Char -> Char 
encryptChar shift c 
| canEncrypt c = chr (ord c + ord shift) 
| isUpper c = c 
| isDigit c = digittrans !! read [c] where digittrans = "*'[email protected]#$%^&"

我々はまた、場合にresultionメカニズムを考える必要があります。だから、read "4"Intの相手に文字列「4」を解析することによって、我々は正しい値を得ることができます大文字でも数字でもない)。その場合は、たとえば文字自体を返すことができます。

encryptChar :: Char -> Char -> Char 
encryptChar shift c 
| canEncrypt c = chr (ord c + ord shift) 
| isUpper c = c 
| isDigit c = digittrans !! read [c] 
    where digittrans = "*'[email protected]#$%^&" 
encryptChar _ c = c
+2

what about '| isNumber c = dict !!この巨大なパターンマッチの代わりに[c] where dict = "* '〜!@#$%^&" 'を読んでください。 – gallais

+1

@gallais:ありがとう。更新しました。 –

5

ありがとう:

if (c == 1) then '\' 

バックスラッシュは文字列リテラルと文字リテラルの中の特殊文字です。次の文字をエスケープするために使用されるので、他の特殊文字を文字列と文字リテラルの内部に使用できます。

ので'\'は、文字通りのバックスラッシュでエスケープ単一引用符内部の文字が続くリテラル文字を、開始単一引用符としてHaskellのパーサで読み取り、その後適切にリテラル文字を終了するには何のエスケープされていない単一引用符がありますされていませんこれは、次の文字が "文字列/文字リテラルの字句エラー"であると不平を言う理由です。

あなたはバックスラッシュ文字のリテラル文字を書くことをしようとしている場合は、あなたがHaskellはにバックスラッシュリテラル文字ではなく、バックスラッシュ修正するとして、それを読んで持つようにバックスラッシュをエスケープするバックスラッシュを使用する必要があります次の文字の解釈。だから、:あなたは、単一引用符文字のリテラル文字を書くことをしようとしている場合は'\\'

は、その後、あなたは内部引用文字リテラルの正しいバックスラッシュでエスケープ単一引用符を持っていましたが、あなたはまだ追加する必要があります文字リテラルを終了するためのエスケープされない引用符。だから、:'\''

関連する問題