akokarev
@akokarev
Начинающий программист

Как в swift преобразовать кодироку строки?

Используя iOS библиотеку Alamofire отправляю на сервер строку. По-умолчанию Alamofire использует кодировку utf-8, сервер ожидает получить cp1251. В итоге кириллица становится нечитаемой.
Подскажите, как правильно отправить строку в котировке cp1251?

let url = "https://greatcomments.server/add"
let parameters = ["comment": "Проверка"]
let headers = ["Content-Type": "application/x-www-form-urlencoded; charset=windows-1251"]
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers)
  • Вопрос задан
  • 4731 просмотр
Решения вопроса 1
doublench21
@doublench21 Куратор тега Swift
let str = "Привет Как дела"  // Внутренняя кодировка Свифта utf-32

let cp1251Data = str.data(using: .windowsCP1251) 
let utf8Data = str.data(using: .utf8)

cp1251Data.count // 15
utf8Data.count // 28

// ***********************************

let session = URLSession.shared
var URL = URL(string: "https://greatcomments.server/add")!
var request = URLRequest(url: URL)
request.httpMethod = "POST"
    
 // Headers
request.addValue("application/x-www-form-urlencoded; charset=windows-1251", forHTTPHeaderField: "Content-Type")

// Form URL-Encoded Body 
let bodyParameters = [
     "comment": "Проверка",
]
let bodyString = bodyParameters.queryParameters
request.httpBody = bodyString.data(using: . win1251, allowLossyConversion: true)

let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in
      if (error == nil) {
        // Success
        let statusCode = (response as! HTTPURLResponse).statusCode
        print("URL Session Task Succeeded: HTTP \(statusCode)")
      }
      else {
        // Failure
        print("URL Session Task Failed: %@", error!.localizedDescription);
      }
    })
task.resume()
session.finishTasksAndInvalidate()


// ***********************************

protocol URLQueryParameterStringConvertible {
  var queryParameters: String {get}
}

extension Dictionary : URLQueryParameterStringConvertible {
  var queryParameters: String {
    var parts: [String] = []
    for (key, value) in self {
      let part = String(format: "%@=%@",
                        String(describing: key).win1251Encoded,
                        String(describing: value).win1251Encoded)
      parts.append(part as String)
    }
    return parts.joined(separator: "&")
  }
  
}

extension URL {
  func appendingQueryParameters(_ parametersDictionary : [String: String]) -> URL {
    let URLString : String = String(format: "%@?%@", self.absoluteString, parametersDictionary.queryParameters)
    return URL(string: URLString)!
  }
}

// Раньше Swift(Foundation) позволял любую строку закодировать в url-encode в любой кодировке. 
// Сейчас же де факто это можно лишь сделать в utf-8. 
// Видимо Apple аргументирует это тем,  что utf-8 - это стандарт в вебе. 

// Да всех остальных случаев нужно писать такую функцию самому. 
// Ниже кодировка в url-encode в windows-1251

extension CharacterSet {
  static let rfc3986Unreserved = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~=&+")
}

extension String.Encoding {
  static let win1251 = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.windowsCyrillic.rawValue)))
}

extension String {
  func addingPercentEncoding(withAllowedCharacters characterSet: CharacterSet, using encoding: String.Encoding) -> String {
    let stringData = self.data(using: encoding, allowLossyConversion: true) ?? Data()
    let percentEscaped = stringData.map {byte->String in
      if characterSet.contains(UnicodeScalar(byte)) {
        return String(UnicodeScalar(byte))
      } else if byte == UInt8(ascii: " ") {
        return "+"
      } else {
        return String(format: "%%%02X", byte)
      }
      }.joined()
    return percentEscaped
  }
  
  var win1251Encoded: String {
    return self.addingPercentEncoding(withAllowedCharacters: .rfc3986Unreserved,  using: . win1251)
  }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы