简体   繁体   English

如何在Swift中的1个字节上编码扩展的ASCII / macOS Roman(字符从128到255)?

[英]How to encode extended ASCII/macOS Roman (characters from 128 to 255) on 1 byte in Swift?

I'm trying to write a .txt file with extended ASCII code, but I need to do it on 8-bit characters. 我正在尝试使用扩展的ASCII代码编写.txt文件,但是我需要对8位字符进行处理。

I'd love to get extended ASCII from Codepage 437 , but I can live with Mac OS Roman . 我很想从Codepage 437获得扩展的ASCII,但是我可以使用Mac OS Roman But as it's operation on numbers, it shouldn't make any difference. 但是,因为它是对数字进行运算,所以不应该有任何区别。

When using Character(UnicodeScalar(unicodePosition)) , it works well for 0 to 127. Each character is 8-bit. 使用Character(UnicodeScalar(unicodePosition)) ,它适用于0到127。每个字符均为8位。 From 128th scalar up, they are not ASCII/macOS Roman and they're encoded on 16 bits. 从第128个标量开始,它们不是ASCII / macOS Roman,而是按16位编码的。

So I can create an array of UInt8 with specific characters that I want to save to file. 因此,我可以创建一个UInt8数组, UInt8包含要保存到文件中的特定字符。

let firstCharacter: UInt8 = 240 // Apple Logo in macOS Roman or "≡" in codepage 437

let secondCharacter: UInt8 = 236 // Infinity symbol on codepage 437 or "I" with two dots in macOS Roman

let listOfCharacters: [UInt8] = [firstCharacter, secondCharacter]

But I have no idea on how to save such a list to a file, and then display it as extendedASCII or macOS Roman encoding. 但是我不知道如何将这样的列表保存到文件中,然后将其显示为扩展ASCII或macOS Roman编码。

I need to operate on this numbers because I'm trying to implement Vigenre Cipher for extended ASCII alphabet (or macOS Roman) and I need the 8-bit input to be 8-bit output so the content of the file have exactly the same file size. 我需要处理此数字,因为我正在尝试为扩展的ASCII字母(或macOS Roman)实现Vigenre Cipher,并且我需要将8位输入转换为8位输出,因此文件内容具有完全相同的文件尺寸。 I have to do it on 256 characters, hence I need extended ascii/macOS Roman. 必须使用256个字符,因此我需要扩展ascii / macOS Roman。

I'd also need to read this kind of file back, so method for reading a textile encoded with extended ASCII would also be appreciated. 我还需要读回这种文件,因此,读取采用扩展ASCII编码的纺织品的方法也将受到赞赏。 I guess that's why there's String.Encoding.nonLossyASCII and not only .ascii ? 我猜这就是为什么会有String.Encoding.nonLossyASCII而不是.ascii吗?

Codepage 437 is available as CFStringEncodings.dosLatinUS and can be converted to a String.Encoding as in How to use Big5 encoding in Swift on iOS : 代码页437可作为CFStringEncodings.dosLatinUS来使用,并且可以转换为String.Encoding如何在iOS上的Swift中使用Big5编码

let cfEnc = CFStringEncodings.dosLatinUS
let nsEnc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(cfEnc.rawValue))
let encoding = String.Encoding(rawValue: nsEnc) // String.Encoding

Now you can convert the bytes to a string and back: 现在,您可以将字节转换为字符串并返回:

let bytes = Data([240, 236])
// CP437 to string:
if let string = String(data: bytes, encoding: encoding) {
    print(string) // ≡∞
    // String to CP437:
    if let bytes2 = string.data(using: encoding) {
        print(Array(bytes2)) // [240, 236]
    }
}

The simple approach is to start with a String instance, convert it to Data using a specified encoding and then convert it the [UInt8] array: 一种简单的方法是从String实例开始,使用指定的编码将其转换为Data ,然后将其转换为[UInt8]数组:

let text = "The quick brown fox ... éâ..."
let data = text.data(using: .macOSRoman)
let characters [UInt8](data)

Be carefule with your encryption. 请注意加密。 Most characters in the range between 0 and 31 cannot be represented in text. 0到31之间的大多数字符不能用文本表示。 They might not occur in the original text. 它们可能不会出现在原始文本中。 But they will appear in the encrypted text. 但是它们将出现在加密的文本中。 If you don't avoid it, the result will be binary data that can no longer be converted to readable text. 如果不避免,结果将是无法再转换为可读文本的二进制数据。

So my final solution looks like this: 所以我的最终解决方案如下所示:

class FileManager {

    let encoding: String.Encoding

    init() {
        let cfEnc = CFStringEncodings.dosLatinUS
        let nsEnc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(cfEnc.rawValue))
        let encoding = String.Encoding(rawValue: nsEnc)
        self.encoding = encoding
    }

    func loadFromFile(path: String) -> Data {
        return NSData(contentsOfFile: path)! as Data
    }

    func saveToFile(data: Data, path: String) {
        let string = dataToPage437String(data: data)
        let fileURL = URL(fileURLWithPath: path)
        try? string?.write(to: fileURL, atomically: false, encoding: encoding)
    }

    func page437StringToData(string: String) -> Data? {
         return string.data(using: encoding)
    }

    private func dataToPage437String(data: Data) -> String? {
        return String(data: data, encoding: encoding)
    }
}
class EncryptionEngine {

    func encrypt(originalData: Data, keyData: Data) -> Data {
        var encryptedData = [UInt8]()

        for (index, byte) in originalData.enumerated() {
            let indexInCurrentBlock = index % keyData.count
            let row = Int(byte)
            let column = Int(keyData[indexInCurrentBlock])
            //for pure Vigenère cipher modifier should be 0
            let modifier = index + 1
            let encryptedCharacter = UInt8((row + column + modifier) % 256)
            encryptedData.append(encryptedCharacter)
        }

        return Data(encryptedData)
    }
}
        let fileManager = FileManager()
        let encryptionEngine = EncryptionEngine()
        let originalData = fileManager.loadFromFile(path: "/Path/test2.txt")
        guard let keyData = fileManager.page437StringToData(string: "keyToEncryptTakenFromTextField") else { return }
        let encryptedData = encryptionEngine.encrypt(originalData: originalData, keyData: keyData)
        fileManager.saveToFile(data: encryptedData, path: "/Path/test_enc.txt")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM