URL 中的片假名字符 G 被错误编码
Katakana character ジ in URL being encoded incorrectly
我需要构建一个 URL,其中包含从我的应用程序服务器接收到的字符串路径,其中包含以下字符:ジ
然而,在 Swift 中,fileURLWithPath
似乎编码不正确。
let path = "ジ"
print(URL(fileURLWithPath: path))
print(URL(fileURLWithPath: path.precomposedStringWithCanonicalMapping))
同时打印:
%E3%82%B7%E3%82%99
这个预期的 URL 路径应该是:
%E3%82%B8
我错过了什么或做错了什么?感谢任何帮助。
您可以使用 dataRepresentation
:
尝试这种方法
if let path = "ジ".data(using: .utf8),
let url = URL(dataRepresentation: path, relativeTo: nil) {
print("\n---> url: \(url) \n") //---> url: %E3%82%B8
}
有两个不同的字符,ジ
和 ジ
。它们可能看起来相同,但它们具有不同的内部表示。
前者是“片假名字母zi”,由单个Unicode标量组成,percent-encodes为%E3%82%B8
。
后者仍然是单个Swift字符,但由两个Unicode标量(“片假名字母si”和“组合浊音标记”)组成,而这两个Unicode标量 percent-encode 到 %E3%82%B7%E3%82%99
.
例如,可以使用 precomposedStringWithCanonicalMapping
规范化字符串中的字符。这可以将具有两个 Unicode 标量的字符转换为具有单个 Unicode 标量的字符。
但是您的本地文件系统(或者,至少 init(fileURLWithPath:)
)分解变音符号。本地文件系统确保变音符号以某种一致的方式编码是合乎逻辑的。 (参见 Diacritics in file names on macOS behave strangely。)为了本次讨论,它们被分解而不是预先组合的事实有点学术性。当您将它发送到服务器时,无论您的本地文件系统中发生了什么,您都希望它预先合成。
现在,您告诉我们“url 路径被服务器拒绝”。那没有意义。人们通常不会向远程服务器提供本地文件系统 URL。人们通常会从本地文件系统 URL 中提取文件名并将其发送到服务器。这可以通过多种方式完成:
您 可以 在将文件名添加到服务器 URL 时使用 precomposedStringWithCanonicalMapping
,并且它尊重该映射,与文件不同URL:
let path = "ジ" // actually `%E3%82%B7%E3%82%99` variant
let url = URL(string: "https://example.com")!
.appendingPathComponent(path.precomposedStringWithCanonicalMapping)
print(url) // https://example.com/%E3%82%B8
如果在请求正文中发送,请使用 precomposedStringWithCanonicalMapping
。例如。如果 multipart/form-data
请求中的 filename
:
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename.precomposedStringWithCanonicalMapping)\"\r\n")
body.append("Content-Type: \(mimeType)\r\n\r\n")
body.append(data)
body.append("\r\n")
现在,这些是关于如何向服务器提供文件名的两个随机示例。你的可能会有所不同。但想法是,当您提供文件名时,您会以规范格式预先组合字符串,而不是依赖于本地文件系统中的文件 URL 使用什么。
但我建议避免使用 URL(fileURLWithPath:)
来操作服务器提供的字符串。它仅在实际引用本地文件系统中的文件时使用。如果你只想 percent-encode 字符串,我建议使用 String
方法 addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
。这不会覆盖 precomposedStringWithCanonicalMapping
输出。
我需要构建一个 URL,其中包含从我的应用程序服务器接收到的字符串路径,其中包含以下字符:ジ
然而,在 Swift 中,fileURLWithPath
似乎编码不正确。
let path = "ジ"
print(URL(fileURLWithPath: path))
print(URL(fileURLWithPath: path.precomposedStringWithCanonicalMapping))
同时打印:
%E3%82%B7%E3%82%99
这个预期的 URL 路径应该是:
%E3%82%B8
我错过了什么或做错了什么?感谢任何帮助。
您可以使用 dataRepresentation
:
if let path = "ジ".data(using: .utf8),
let url = URL(dataRepresentation: path, relativeTo: nil) {
print("\n---> url: \(url) \n") //---> url: %E3%82%B8
}
有两个不同的字符,ジ
和 ジ
。它们可能看起来相同,但它们具有不同的内部表示。
前者是“片假名字母zi”,由单个Unicode标量组成,percent-encodes为
%E3%82%B8
。后者仍然是单个Swift字符,但由两个Unicode标量(“片假名字母si”和“组合浊音标记”)组成,而这两个Unicode标量 percent-encode 到
%E3%82%B7%E3%82%99
.
例如,可以使用 precomposedStringWithCanonicalMapping
规范化字符串中的字符。这可以将具有两个 Unicode 标量的字符转换为具有单个 Unicode 标量的字符。
但是您的本地文件系统(或者,至少 init(fileURLWithPath:)
)分解变音符号。本地文件系统确保变音符号以某种一致的方式编码是合乎逻辑的。 (参见 Diacritics in file names on macOS behave strangely。)为了本次讨论,它们被分解而不是预先组合的事实有点学术性。当您将它发送到服务器时,无论您的本地文件系统中发生了什么,您都希望它预先合成。
现在,您告诉我们“url 路径被服务器拒绝”。那没有意义。人们通常不会向远程服务器提供本地文件系统 URL。人们通常会从本地文件系统 URL 中提取文件名并将其发送到服务器。这可以通过多种方式完成:
您 可以 在将文件名添加到服务器 URL 时使用
precomposedStringWithCanonicalMapping
,并且它尊重该映射,与文件不同URL:let path = "ジ" // actually `%E3%82%B7%E3%82%99` variant let url = URL(string: "https://example.com")! .appendingPathComponent(path.precomposedStringWithCanonicalMapping) print(url) // https://example.com/%E3%82%B8
如果在请求正文中发送,请使用
precomposedStringWithCanonicalMapping
。例如。如果multipart/form-data
请求中的filename
:body.append("--\(boundary)\r\n") body.append("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename.precomposedStringWithCanonicalMapping)\"\r\n") body.append("Content-Type: \(mimeType)\r\n\r\n") body.append(data) body.append("\r\n")
现在,这些是关于如何向服务器提供文件名的两个随机示例。你的可能会有所不同。但想法是,当您提供文件名时,您会以规范格式预先组合字符串,而不是依赖于本地文件系统中的文件 URL 使用什么。
但我建议避免使用 URL(fileURLWithPath:)
来操作服务器提供的字符串。它仅在实际引用本地文件系统中的文件时使用。如果你只想 percent-encode 字符串,我建议使用 String
方法 addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
。这不会覆盖 precomposedStringWithCanonicalMapping
输出。