Простым способом было бы использовать метод (NS)String
stringByRemovingPercentEncoding
для этой цели. Это наблюдалось в decoding quoted-printables, , поэтому первое решение - это, в основном, перевод ответов в , что нить для Swift.
Идея состоит в том, чтобы заменить кодировку «= NN» с кавычками на кодировку процентов «% NN», а затем использовать существующий метод для удаления процентной кодировки.
Линии продолжения обрабатываются отдельно. Кроме того, проценты символов во входной строке должны быть закодированы сначала, , иначе они будут рассматриваться как ведущий символ в процентах .
func decodeQuotedPrintable(message : String) -> String? {
return message
.stringByReplacingOccurrencesOfString("=\r\n", withString: "")
.stringByReplacingOccurrencesOfString("=\n", withString: "")
.stringByReplacingOccurrencesOfString("%", withString: "%25")
.stringByReplacingOccurrencesOfString("=", withString: "%")
.stringByRemovingPercentEncoding
}
Функция возвращает необязательную строку, которая является nil
для недопустимого ввода. Неправильный ввод может быть:
- А «=» символ, который не следуют два шестнадцатеричных цифр, например, "= XX".
- Последовательность «= NN», которая не декодируется до действительной последовательности UTF-8, , например. "= Е2 = 64".
Примеры:
if let decoded = decodeQuotedPrintable("=C2=A31,000") {
print(decoded) // £1,000
}
if let decoded = decodeQuotedPrintable("=E2=80=9CHello =E2=80=A6 world!=E2=80=9D") {
print(decoded) // “Hello … world!”
}
Update 1: Приведенный выше код предполагает, что сообщение использует UTF-8 кодировку процитировать не-ASCII символы, как и в большинстве ваших примеров : C2 A3
- кодировка UTF-8 для «£», E2 80 A4
- кодировка UTF-8 для …
.
Если ввод "Rub=E9n"
, то сообщение использует кодировку Windows-1252. Для декодирования, что правильно, вы должны заменить
.stringByRemovingPercentEncoding
по
.stringByReplacingPercentEscapesUsingEncoding(NSWindowsCP1252StringEncoding)
Есть также способы обнаружения кодировки из поля заголовка «Content-Type», сравните, например, https://stackoverflow.com/a/32051684/1187415.
Update 2:stringByReplacingPercentEscapesUsingEncoding
метод помечен как устаревший, поэтому приведенный выше код всегда будет генерировать предупреждение компилятора. К сожалению, похоже, что Apple не предоставил альтернативный метод .
Так вот новый, полностью автономный метод декодирования, который не вызывает предупреждения о компиляторе. На этот раз я написал в качестве метода расширения для String
. Объяснение комментариев содержится в коде .
extension String {
/// Returns a new string made by removing in the `String` all "soft line
/// breaks" and replacing all quoted-printable escape sequences with the
/// matching characters as determined by a given encoding.
/// - parameter encoding: A string encoding. The default is UTF-8.
/// - returns: The decoded string, or `nil` for invalid input.
func decodeQuotedPrintable(encoding enc : NSStringEncoding = NSUTF8StringEncoding) -> String? {
// Handle soft line breaks, then replace quoted-printable escape sequences.
return self
.stringByReplacingOccurrencesOfString("=\r\n", withString: "")
.stringByReplacingOccurrencesOfString("=\n", withString: "")
.decodeQuotedPrintableSequences(enc)
}
/// Helper function doing the real work.
/// Decode all "=HH" sequences with respect to the given encoding.
private func decodeQuotedPrintableSequences(enc : NSStringEncoding) -> String? {
var result = ""
var position = startIndex
// Find the next "=" and copy characters preceding it to the result:
while let range = rangeOfString("=", range: position ..< endIndex) {
result.appendContentsOf(self[position ..< range.startIndex])
position = range.startIndex
// Decode one or more successive "=HH" sequences to a byte array:
let bytes = NSMutableData()
repeat {
let hexCode = self[position.advancedBy(1) ..< position.advancedBy(3, limit: endIndex)]
if hexCode.characters.count < 2 {
return nil // Incomplete hex code
}
guard var byte = UInt8(hexCode, radix: 16) else {
return nil // Invalid hex code
}
bytes.appendBytes(&byte, length: 1)
position = position.advancedBy(3)
} while position != endIndex && self[position] == "="
// Convert the byte array to a string, and append it to the result:
guard let dec = String(data: bytes, encoding: enc) else {
return nil // Decoded bytes not valid in the given encoding
}
result.appendContentsOf(dec)
}
// Copy remaining characters to the result:
result.appendContentsOf(self[position ..< endIndex])
return result
}
}
Пример использования:
if let decoded = "=C2=A31,000".decodeQuotedPrintable() {
print(decoded) // £1,000
}
if let decoded = "=E2=80=9CHello =E2=80=A6 world!=E2=80=9D".decodeQuotedPrintable() {
print(decoded) // “Hello … world!”
}
if let decoded = "Rub=E9n".decodeQuotedPrintable(encoding: NSWindowsCP1252StringEncoding) {
print(decoded) // Rubén
}
Это не полное решение, но я бы хотел, чтобы убедиться, что вы уже видели этот ответ на несколько иной проблема: http://stackoverflow.com/a/19088341/4323 –
Базовая кодировка 64 Я хорош, это текст/plain; quoted-printable, с которыми у меня возникла проблема. Спасибо – iphaaw