2017-03-08 3 views
0

Ich habe eine Folge von binären Werten, z. "010010000110010101111001". Gibt es eine einfache Möglichkeit, diese Zeichenfolge in ihre ASCII-Darstellung zu konvertieren, um (in diesem Fall) "Hey" zu erhalten?Swift - Konvertiere eine binäre Zeichenfolge in ihre ASCII-Werte

gefunden Nur die andere Richtung oder Dinge für Integer:

let binary = "11001" 
    if let number = Int(binary, radix: 2) { 
     print(number) // Output: 25 
    } 

jemand eine gute und effiziente Lösung für diesen Fall wissen Sie?

+0

Ich denke, Ihre Lösung zu einfach ist. – javimuu

+0

das ist nicht meine lösung, ich brauche eine o erhalten ascii werte nicht ints – Appygix

Antwort

3

Möglicherweise müssen Sie die eingegebenen Binärziffern in 8-Bit-Chunks aufteilen und dann jeden Chunk in ein ASCII-Zeichen konvertieren. Ich kann nicht glauben, von einer Super-einfachen Art und Weise:

var binaryBits = "010010000110010101111001" 

var index = binaryBits.startIndex 
var result: String = "" 
for _ in 0..<binaryBits.characters.count/8 { 
    let nextIndex = binaryBits.index(index, offsetBy: 8) 
    let charBits = binaryBits[index..<nextIndex] 
    result += String(UnicodeScalar(UInt8(charBits, radix: 2)!)) 
    index = nextIndex 
} 
print(result) //->Hey 
+0

Können Sie mit der Umkehrung dieser helfen? – rv7284

+0

@ rv7284, Starten Sie lieber einen neuen Thread. Es kann ein etwas größerer Code sein als ein Kommentar. – OOPer

+0

Ich habe einen neuen Thread erstellt – rv7284

1

funktioniert im Grunde die gleichen wie OOPer-Lösung, aber er/sie war schneller und hat einen kürzeren, eleganten Ansatz :-)

func getASCIIString(from binaryString: String) -> String? { 

    guard binaryString.characters.count % 8 == 0 else { 
     return nil 
    } 

    var asciiCharacters = [String]() 
    var asciiString = "" 

    let startIndex = binaryString.startIndex 
    var currentLowerIndex = startIndex 

    while currentLowerIndex < binaryString.endIndex { 

     let currentUpperIndex = binaryString.index(currentLowerIndex, offsetBy: 8) 
     let character = binaryString.substring(with: Range(uncheckedBounds: (lower: currentLowerIndex, upper: currentUpperIndex))) 
     asciiCharacters.append(character) 
     currentLowerIndex = currentUpperIndex 
    } 

    for asciiChar in asciiCharacters { 
     if let number = UInt8(asciiChar, radix: 2) { 
      let character = String(describing: UnicodeScalar(number)) 
      asciiString.append(character) 
     } else { 
      return nil 
     } 
    } 

    return asciiString 
} 

let binaryString = "010010000110010101111001" 

if let asciiString = getASCIIString(from: binaryString) { 
    print(asciiString) // Hey 
} 
6

Eine Variante von @OOPer's solution wäre eine bedingte Bindung while Schleife und index(_:offsetBy:limitedBy:) zu verwenden, um über die 8 Zeichen Teilstrings iterieren, unter Ausnutzung der Tatsache, dass index(_:offsetBy:limitedBy:)nil zurückgibt, wenn Sie versuchen, über das Limit hinaus zu kommen.

let binaryBits = "010010000110010101111001" 

var result = "" 
var index = binaryBits.startIndex 

while let next = binaryBits.index(index, offsetBy: 8, limitedBy: binaryBits.endIndex) { 
    let asciiCode = UInt8(binaryBits[index..<next], radix: 2)! 
    result.append(Character(UnicodeScalar(asciiCode))) 
    index = next 
} 

print(result) // Hey 

Bitte beachte, dass wir über Character fahren anstatt String in dem Zwischenschritt - das ist einfach die Tatsache zunutze zu tragen, dass Characteris specially optimised für Fälle, in denen die UTF-8-Darstellung in 63 Bytes paßt, das ist der Fall hier. Dies spart die Zwischenspeicherung eines Zwischenpuffers für jedes Zeichen.


Rein zum Spaß es könnte ein anderer Ansatz sein sequence(state:next:) zu verwenden, um eine Folge von den Start- und Zielindizes jeder Teilkette zu erstellen, und dann reduce, um die resultierenden Zeichen zusammen in ein verketten string:

let binaryBits = "010010000110010101111001" 

// returns a lazily evaluated sequence of the start and end indices for each substring 
// of 8 characters. 
let indices = sequence(state: binaryBits.startIndex, next: { 
    index -> (index: String.Index, nextIndex: String.Index)? in 

    let previousIndex = index 

    // Advance the current index – if it didn't go past the limit, then return the 
    // current index along with the advanced index as a new element of the sequence. 
    return binaryBits.characters.formIndex(&index, offsetBy: 8, limitedBy: binaryBits.endIndex) ? (previousIndex, index) : nil 
}) 

// iterate over the indices, concatenating the resultant characters together. 
let result = indices.reduce("") { 
    $0 + String(UnicodeScalar(UInt8(binaryBits[$1.index..<$1.nextIndex], radix: 2)!)) 
} 

print(result) // Hey 

auf dem Gesicht von ihm, scheint dies viel weniger effizient als die erste Lösung zu sein (aufgrund der Tatsache, dass reduce bei jeder Iteration die Zeichenfolge kopieren soll) - aber es scheint der Compiler in der Lage, Führen Sie einige Optimierungen durch, um es nicht viel langsamer als die erste Lösung zu machen.

+0

Ich bin ein echter Fan von 'sequenz (state: next)', auch wenn es normalerweise dazu neigt, w.r.t. Leistung im Vergleich zu eher "klassischen" Ansätzen. Übrigens sollte meine Abstimmung (oder eine noch zu aktualisierende kurz zuvor) über diese gute Antwort Sie über 999 Swift-Tag Upvotes drücken. So etwas vorab auf dem Goldabzeichen! : D – dfri

+0

@dfri Ja, ich würde es auf jeden Fall häufiger verwenden, wenn die Leistung kein Problem ist und die Syntax etwas weniger abschreckend ist, bevorzuge ich immer die eher "klassischen" Ansätze :) Und danke für die +1: D Leider hast du die 1000. Upvote um ein oder zwei Minuten verpasst!Du hast den 1001. Upvote;) Freue mich schon auf den mächtigen Mjölnir :) – Hamish

+1

Ja, ich auch :) verdammt, der 1000. wäre ordentlich gewesen! Heh ja mein gelöschter Kommentar hatte etwas Verwirrung w.r.t. die Tatsache, dass nur das silberne Abzeichen auf deinem Profil gezeigt wurde, aber ich schätze, das Gold wird bald dort erscheinen :) Der erste Hammerschlag wird hoffentlich viel Befriedigung geben! – dfri

1

Ein anderer Ansatz

let bytes_string: String = "010010000110010101111001" 
var range_count: Int = 0 

let characters_array: [String] = Array(bytes_string.characters).map({ String($0)}) 

var conversion: String = "" 

repeat 
{ 
    let sub_range = characters_array[range_count ..< (range_count + 8)] 
    let sub_string: String = sub_range.reduce("") { $0 + $1 } 

    let character: String = String(UnicodeScalar(UInt8(sub_string, radix: 2)!)) 

    conversion += character 

    range_count += 8 

} while range_count < characters_array.count 

print(conversion) 
Verwandte Themen