Skip to main content
Code Review

Return to Answer

deleted 66 characters in body
Source Link
Martin R
  • 24.2k
  • 2
  • 37
  • 95
var value = k % 26
if value < 0 { value += 26 }
  • Use a switch-statement with range patterns instead of the if-conditions:

     switch code {
     case 65...90:
     // ...
     case 97...122:
     // ...
     default:
     // ...
     }
    
  • Use constants instead of the literal numbers, e.g.

     let uppercaseAletter_A = 65
     let uppercaseZletter_Z = 90
     let lowercaseAletter_a = 97
     let lowercaseZletter_z = 122
    
var value = k % 26
if value < 0 { value += 26 }
  • Use a switch-statement with range patterns instead of the if-conditions:

     switch code {
     case 65...90:
     // ...
     case 97...122:
     // ...
     default:
     // ...
     }
    
  • Use constants instead of the literal numbers, e.g.

     let uppercaseA = 65
     let uppercaseZ = 90
     let lowercaseA = 97
     let lowercaseZ = 122
    
var value = k % 26
if value < 0 { value += 26 }
  • Use a switch-statement with range patterns instead of the if-conditions:

     switch code {
     case 65...90:
     // ...
     case 97...122:
     // ...
     default:
     // ...
     }
    
  • Use constants instead of the literal numbers, e.g.

     let letter_A = 65
     let letter_Z = 90
     let letter_a = 97
     let letter_z = 122
    
Source Link
Martin R
  • 24.2k
  • 2
  • 37
  • 95

Enumerating UTF-8 characters: Your code uses two nested loops to encrypt letters (based on the UTF-8 code):

var eMessage = ""
let arr = messageToCipher.characters.map { String(0ドル) }
for ch in arr {
 for code in String(ch).utf8 {
 if (65<=code && code<=90) || (97<=code && code<=122) {
 // ... translate `code` and append to `eMessage` ...
 }
 else{
 eMessage = eMessage + ch
 }
 }
}

This is unnecessary complicated and has an unwanted side effect if the message contains non-ASCII characters (which are encoded as 2 or more UTF-8 code units):

print(cipher(messageToCipher: "Γ€ € πŸ˜€ πŸ‡§πŸ‡©", k: 2) )
// ÀÀ €€€ πŸ˜€πŸ˜€πŸ˜€πŸ˜€ πŸ‡§πŸ‡©πŸ‡§πŸ‡©πŸ‡§πŸ‡©πŸ‡§πŸ‡©πŸ‡§πŸ‡©πŸ‡§πŸ‡©πŸ‡§πŸ‡©πŸ‡§πŸ‡©

This could be solved by adding a break in the else-case. The better solution is to enumerate the UTF-8 code units directly:

var encoded: [UInt8] = []
for code in messageToCipher.utf8 {
 if (65<=code && code<=90) || (97<=code && code<=122) {
 // ... translate `code` and append to `encoded` ...
 }
 else{
 encoded.append(code)
 }
}
return String(bytes: encoded, encoding: .utf8)!

Code duplication: There is some duplicate code in

 if k > 26{
 let value = k % 26 == 0 ? k / 26 : k % 26
 var pCode = ((Int(code)) + (value))
 if (pCode > 122 && (97<=code && code<=122)) || (pCode > 90 && (65<=code && code<=90)) {
 pCode = pCode - 26
 }
 let s = String(UnicodeScalar(UInt8(pCode)))
 eMessage = eMessage + s
 }else
 {
 var pCode = Int(code) + k
 if (pCode > 122 && (97<=code && code<=122)) || (pCode > 90 && (65<=code && code<=90)) {
 pCode = pCode - 26
 }
 let s = String(UnicodeScalar(UInt8(pCode)))
 eMessage = eMessage + s
 }

which is not necessary. The if-part works for the case k <= 26 as well.

Exceptional key values: The special handling of the case k % 26 == 0 causes unexpected results:

print(cipher(messageToCipher: "abc xyz ABC XYZ", k: 26) ) // abc xyz ABC XYZ
print(cipher(messageToCipher: "abc xyz ABC XYZ", k: 52) ) // cde zab CDE ZAB

and is not needed. Negative key values are not handled at all:

print(cipher(messageToCipher: "abc xyz ABC XYZ", k: -2) ) // _`a vwx ?@A VWX
print(cipher(messageToCipher: "abc xyz ABC XYZ", k: -200) )
// Fatal error: Negative value is not representable

Both issues can be solved by computing the remainder of k modulo 26, as a number in the range 0...25:

 var value = k % 26
 if value < 0 { value += 26 }

In addition, this computation can be done once, before entering the loop.

Other issues:

  • I would use some different argument/variable names, e.g. message instead of messageToCipher (it is clear from the context and the function name that this string should be encrypted), or key instead of k.

  • There are unnecessary parentheses, e.g. in

     var pCode = ((Int(code)) + (value))
    
  • The usage of white space is not consistent, e.g. in

     if (pCode > 122 && (97<=code && code<=122)) || (pCode > 90 && (65<=code && code<=90)) {
    

Summarizing the suggestions so far, we have

func cipher(message: String, key: Int) -> String {
 
 var offset = key % 26
 if offset < 0 { offset += 26 }
 var encoded: [UInt8] = []
 for code in message.utf8 {
 if (65 <= code && code <= 90) || (97 <= code && code <= 122) {
 var pCode = Int(code) + offset
 if (pCode > 122 && (97 <= code && code <= 122)) || (pCode > 90 && (65 <= code && code <= 90)) {
 pCode -= 26
 }
 encoded.append(UInt8(pCode))
 } else {
 encoded.append(code)
 }
 }
 return String(bytes: encoded, encoding: .utf8)!
}

Make it functional: If the encryption of a single character is moved to a separate function then one can apply this to the UTF-8 view with map():

func cipher(message: String, key: Int) -> String {
 
 var offset = key % 26
 if offset < 0 { offset += 26 }
 
 func utf8encrypt(code: UInt8) -> UInt8 {
 // ... compute and return encrypted character ...
 }
 
 return String(bytes: message.utf8.map(utf8encrypt), encoding: .utf8)!
}

Further suggestions:

  • Use a switch-statement with range patterns instead of the if-conditions:

     switch code {
     case 65...90:
     // ...
     case 97...122:
     // ...
     default:
     // ...
     }
    
  • Use constants instead of the literal numbers, e.g.

     let uppercaseA = 65
     let uppercaseZ = 90
     let lowercaseA = 97
     let lowercaseZ = 122
    

so that a future reader of your code does not have to guess what the numbers stand for.

default

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /