2016-06-10 94 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