【问题标题】:swift euc-kr korean encoding not working. But works in pythonswift euc-kr 韩国编码不起作用。但适用于python
【发布时间】:2016-12-21 19:40:37
【问题描述】:

我正在编写一些代码来解析来自使用euc-kr 韩国编码器编码的服务器的韩国文本。

当我在 Python 中执行相同的编码时,它会按预期工作。 但是当我按照以下方式进行操作时,编码不起作用。结果是不可读的。

在 Python 中:

string = u'안녕하세요.'.encode('eucKR') 

在斯威夫特中:

let encoding:UInt =  CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(
        CFStringEncodings.EUC_KR.rawValue))

let encodedData = "안녕하세요.".data(using: String.Encoding(rawValue: encoding))!

这两种编码有什么区别?

以下是 python 和 swift 的完整源代码。我仍然坚持编码部分。问题是否与 alamofire 发布请求有关?

Python:

import requests
from pattern import web

string = u'저는 내일 바빠서 학교에 못갑니다.'.encode('eucKR')
r = requests.post("http://nlp.korea.ac.kr/~demo/dglee/komatag.php", data={'formradio1': '', 'formradio2': 'ems', 'textarea': string})
dom = web.Element(r.text)
main = dom('tr')
for item in main:
    result = web.plaintext(item.source)
    a = result.encode('ISO-8859-1')
    t=a.decode('eucKR')
    print(t)

斯威夫特:

    override func viewDidLoad() {

        let string: NSString = NSString(string: "안녕하세요")
        let encodedEucKr = stringToEuckrString(stringValue: string as String)
        print(encodedEucKr)

        Alamofire.request("http://nlp.korea.ac.kr/~demo/dglee/komatag.php", method: .post, parameters: ["formradio1":"", "formradio2":"ems", "textarea": encodedEucKr], headers: nil).responseString { response in

            switch(response.result) {
            case .success(_):
                if let data = response.result.value{
                    print(response.result.value)
                }
                break

            case .failure(_):
                print(response.result.error)
                break

            }
        }

    }


func stringToEuckrString(stringValue: String) -> String {

    let encoding:UInt = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(
        CFStringEncodings.EUC_KR.rawValue))

    let encodedData = stringValue.data(using: String.Encoding(rawValue: encoding))!

    let attributedString = try? NSAttributedString(data: encodedData, options:[:],        documentAttributes: nil)

    if let _ = attributedString {
        return attributedString!.string
    } else {
        return ""
    }
}

【问题讨论】:

  • 您是如何检查结果的?据我在 May Mac(Xcode 8.2.1 和 python 2.7.10)上测试,两个结果都包含完全相同的字节序列。
  • 你能找出解决我问题的方法吗?我已经坚持了大约3个小时。仍然没有运气。
  • 你在 EUC-KR 中发送 POST 请求的方式是完全错误的,但就目前而言,我没有足够的时间来写一个答案。等待可以帮助您的人(或稍后为我)。现在您的问题似乎已经准备好寻找解决问题的方法了。
  • 非常感谢您的帮助。这几乎是我第一次使用stackoverflow。稍后我会等待某人或您的答复。

标签: swift encoding http-request


【解决方案1】:

这并不容易,有两个原因......

  1. 在 EUC-KR 中发送表单数据在现代网络技术和标准中不被视为符合标准。

  2. 从您的服务器发送的响应有点损坏,因为 Swift 无法将结果解码为有效的 EUC-KR 文本。

    (这似乎是您的服务器端代码的错误。)

无论如何,当您需要向 EUC-KR 中的服务器发送基于 Web 表单的请求时:

  • 从原始创建 EUC-KR 字节序列
  • 百分比转义它。你可能需要自己做
  • 将整个请求放入 HTTP 请求正文中
  • 添加正确的 MIME 类型标头

一些细节取决于服务器。没用过Alamofire,不知道Alamofire是否支持这种东西。

这里我给你看一个使用普通URLSession的例子:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    sendRequest(string: "안녕하세요")
}

func sendRequest(string: String) {
    let rawEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.EUC_KR.rawValue))
    let encoding = String.Encoding(rawValue: rawEncoding)
    
    let url = URL(string: "http://nlp.korea.ac.kr/~demo/dglee/komatag.php")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    //Create an EUC-KR byte sequece
    let eucKRStringData = string.data(using: encoding) ?? Data()
    //Percent-escape, you need to do it by yourself
    //(Though, most servers accept non-escaped binary data with its own rules...)
    let eucKRStringPercentEscaped = eucKRStringData.map {byte->String in
        if byte >= UInt8(ascii: "A") && byte <= UInt8(ascii: "Z")
        || byte >= UInt8(ascii: "a") && byte <= UInt8(ascii: "z")
        || byte >= UInt8(ascii: "0") && byte <= UInt8(ascii: "9")
        || byte == UInt8(ascii: "_") || byte == UInt8(ascii: ".") || byte == UInt8(ascii: "-")
        {
            return String(Character(UnicodeScalar(UInt32(byte))!))
        } else if byte == UInt8(ascii: " ") {
            return "+"
        } else {
            return String(format: "%%%02X", byte)
        }
    }.joined()
    //In application/x-www-form-urlencoded format, you send data in a URL-query like format.
    let paramString = "formradio1=&formradio2=ems&textarea=\(eucKRStringPercentEscaped)"
    //As all non-ASCII characters are percent-escaped, .isoLatin1 works well here.
    let bodyData = paramString.data(using: .isoLatin1)!
    //Form data needs to be sent as a body of HTTP protocol.
    request.httpBody = bodyData
    //MIME type for usual form data is "application/x-www-form-urlencoded".
    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    //URLRequest is ready and you can start dataTask here.
    let task = URLSession.shared.dataTask(with: request) {data, response, error in
        if let error = error {
            print("Error:", error)
        }
        if let response = response {
            print("Response:", response)
        }
        //The response may not be valid EUC-KR; you need to decode it while accepting invalid bytes.
        if let data = data {
            var result = ""
            var i = 0
            while i < data.count{
                let ch = data[i]
                if ch < 0x80 {
                    result += String(Character(UnicodeScalar(UInt32(ch))!))
                } else if
                    i + 2 <= data.count,
                    let ch2 = String(data: data.subdata(in: i..<i+2), encoding: encoding)
                {
                    result += ch2
                    i += 1
                } else {
                    result += "?"
                }
                i += 1
            }
            print("Result:", result)
        }
    }
    //Do not forget to resume the created task.
    task.resume()
    //And remember you should not do anything after you invoke an async task.
}

如果您的服务器端可以正确处理 UTF-8 请求和响应,那么上面的代码可以简单得多。在 Web 服务中使用 EUC-KR 有点过时了。你最好尽快采用 UTF-8。

【讨论】:

  • 天哪,你真是天才。非常感谢您抽出宝贵的时间来解决我的问题。看起来好复杂。我永远不会自己解决。再一次非常感谢你。我知道服务器真的很旧,但只有一种方法可以将它用于我的应用程序。
猜你喜欢
  • 2018-01-13
  • 2018-03-27
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
  • 1970-01-01
  • 2016-11-08
  • 1970-01-01
相关资源
最近更新 更多