2016-06-10 66 views
3

我想創建一個函數,它接收一個字符串並返回一個字符串,並用字母后面的13個字母替換一個字母(ROT13)。我發現了很多例子,不幸的是,由於各種錯誤,我無法讓它工作。例如,這一個:如何在Swift中實現ROT13函數?

var key = [String:String]() // EDITED 
let uppercase = Array(arrayLiteral: "ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
let lowercase = Array(arrayLiteral: "abcdefghijklmnopqrstuvwxyz") 
for i in 0 ..< 26 { 
    key[uppercase[i]] = uppercase[(i + 13) % 26] 
    key[lowercase[i]] = lowercase[(i + 13) % 26] 
} 

func rot13(s: String) -> String { 
    return String(map(s, { key[$0] ?? $0 })) 
} 
+0

爲什麼不乾脆讓按鍵陣列一個字符串數組? – user2277872

+0

你試圖用'$ 0'來獲得'key'中的元素,這是一個'Character',而不是'Int' – Alexander

+0

謝謝。我現在將密鑰設置爲一個字符串數組。現在有一個字符串seq問題:「extraneous argument label'seq:'in call」 – Cue

回答

5

其實你的映射Character S的初步做法是好的:

var key = [Character: Character]() 

但兩個數組必須是Characters數組:

let uppercase = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters) 
let lowercase = Array("abcdefghijklmnopqrstuvwxyz".characters) 

備註:您(幾乎)不想致電xxxLiteral:初始化程序 明確。這樣做是(幾乎)總是躲在實際問題)

現在你的代碼來填充字典的工作:

for i in 0 ..< 26 { 
    key[uppercase[i]] = uppercase[(i + 13) % 26] 
    key[lowercase[i]] = lowercase[(i + 13) % 26] 
} 

和轉化的字符串是可以做到

//      map 
// String --> Characters ---> Characters -> String 

func rot13(s: String) -> String { 
    return String(s.characters.map { key[$0] ?? $0 }) 
} 
+0

感謝Martin,現在一切都很清楚。 – Cue

5

這裏的另一個方法,它不使用查找數組:

let input = "Hello World" 

func rot13(unicodeScalar: UnicodeScalar) -> UnicodeScalar { 
    var result = unicodeScalar.value 

    if 65...90 ~= result { //Detect capital A ... Z 
     result = (result + 13 - 65) % 26 + 65 
    } 
    else if 97 ... 122 ~= result { //Detect lowercase a ... z 
     result = (result + 13 - 97) % 26 + 97 
    } 

    return UnicodeScalar(result) 
} 

func rot13(_ input: String) -> String { 
    let resultUSs = input.unicodeScalars.map(rot13) 

    var resultUSV = String.UnicodeScalarView() 
    resultUSV.appendContentsOf(resultUSs) //for Swift 2.2 
    //resultUSV.append(contentsOf: resultUSs) //for Swift 3.0 
    return String(resultUSV) 
} 

let output = rot13(input) 

print(output) 
+1

你的Swift 3正在展示。您可能需要注意'resultUSV.appendContentsOf(resultUSs)'爲Swift 2.2的兼容性。 – vacawama

+0

啊,是的,我在IBM的Swift沙箱中寫這個,這是Swift 3只有 – Alexander

+0

是的,我希望他們會讓你選擇Swift 2.2與Swift 3.這將是一段時間的過渡時間,直到Xcode 8是GM。 – vacawama

3

這是@AMomch的替代版本它採用了switch少數學和ilov的rot13消除幻數:

func rot13(unicodeScalar: UnicodeScalar) -> Character { 
    var result = unicodeScalar.value 

    switch unicodeScalar { 
    case "A"..."M", "a"..."m": 
     result += 13 
    case "N"..."Z", "n"..."z": 
     result -= 13 
    default: 
     break 
    } 

    return Character(UnicodeScalar(result)) 
} 

func rot13(input: String) -> String { 
    return String(input.unicodeScalars.map(rot13)) 
} 

print(rot13("Uryyb, jbeyq!")) // "Hello, world!" 

泛化rotN

我已經讓他們採取採取rot13功能上面,並推廣他們rotN一組ClosedInterval<UnicodeScalar>。這允許您以非常直接的方式實施rot13,rot47,rot5以及rot13rot5的組合。

func rotN(unicodeScalar: UnicodeScalar, intervals:[ClosedInterval<UnicodeScalar>]) -> Character { 
    var result = unicodeScalar.value 

    for interval in intervals { 
     let half = (interval.end.value - interval.start.value + 1)/2 
     let halfway = UnicodeScalar(interval.start.value + half) 

     switch unicodeScalar { 
     case interval.start..<halfway: 
      result += half 
     case halfway...interval.end: 
      result -= half 
     default: 
      break 
     } 
    } 

    return Character(UnicodeScalar(result)) 
} 

func rotN(input: String, intervals:[ClosedInterval<UnicodeScalar>]) -> String { 
    return String(input.unicodeScalars.map {rotN($0, intervals: intervals)}) 
} 

func rot13(input: String) -> String { 
    return rotN(input, intervals:["A"..."Z", "a"..."z"]) 
} 

func rot47(input: String) -> String { 
    return rotN(input, intervals:["!"..."~"]) 
} 

func rot5(input: String) -> String { 
    return rotN(input, intervals:["0"..."9"]) 
} 

func rot13and5(input: String) -> String { 
    return rotN(input, intervals:["A"..."Z", "a"..."z", "0"..."9"]) 
} 

print(rot13("Uryyb, jbeyq!"))  // "Hello, world!" 
print(rot47("%96 BF:4< [email protected]? [email protected]")) // "The quick brown fox" 
print(rot5("6 + 7 = 8"))    // "1 + 2 = 3" 
print(rot13and5("Whyl 9, 6221"))  // "July 4, 1776" 

這是基於的rotN版本在原有@AMomchilov'srot13

func rotN(unicodeScalar: UnicodeScalar, intervals:[ClosedInterval<UnicodeScalar>]) -> UnicodeScalar { 
    var result = unicodeScalar.value 

    for interval in intervals { 
     let start = interval.start.value 
     let length = interval.end.value - start + 1 

     if interval ~= unicodeScalar { 
      result = (result + length/2 - start) % length + start 
     } 
    } 

    return UnicodeScalar(result) 
} 


func rotN(input: String, intervals:[ClosedInterval<UnicodeScalar>]) -> String { 
    return String(input.unicodeScalars.map {Character(rotN($0, intervals:intervals))}) 
} 
+1

Ooo這是一個有趣的方法。我喜歡範圍檢查的開關。我忘了這是可能的;它非常有用!我不是解除mod 13的解決方法的粉絲,因爲它很難將其推廣到rotN。我認爲更好的解決方案是將我的2條數學線分解爲單獨的參數化函數。 – Alexander

+0

@AMomchilov,我已經採取了你的挑戰,並推廣到'rotN' :-)。 – vacawama

+0

還不錯,但是我仍然追求避免'%'增加不必要的複雜性 – Alexander