A
A
Anton Kokarev2018-07-09 01:08:42
Character encoding
Anton Kokarev, 2018-07-09 01:08:42

How to convert string encoding in swift?

Using the Alamofire iOS library, I send a string to the server. By default, Alamofire uses utf-8 encoding, the server expects to receive cp1251. As a result, the Cyrillic alphabet becomes unreadable.
Can you tell me how to correctly send a string in cp1251 quote?

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)

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
doublench21, 2018-07-09
@akokarev

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)
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question