【问题标题】:Firebase or Swift not detecting umlautsFirebase 或 Swift 未检测到变音符号
【发布时间】:2016-08-18 19:41:04
【问题描述】:

我在Firebase Database/Storage 中发现了一些最奇怪的东西。问题是我不知道 Firebase 或 Swift 是否没有检测到变音符号,例如(ä、ö、ü)。

我使用 Firebase 做了一些简单的事情,例如将图像上传到 Firebase 存储,然后将它们下载到 tableview。例如,我的一些 .png 文件的标题中有变音符号 (Röda.png)。

所以如果我下载它们,现在就会出现问题。我唯一的下载urlnil 是文件名是否包含我正在谈论的变音符号。

所以我尝试了一些替代方法,例如 HTML ö - ö。但这不起作用。你们能给我一些建议吗?我不能使用ö - oü - u 等。

这是当urlnil 时尝试将一些值设置到 Firebase 时的代码:

FIRStorage.storage().reference()
          .child("\(productImageref!).png")
          .downloadURLWithCompletion({(url, error)in


FIRDatabase.database().reference()
           .child("Snuses").child(productImageref!).child("productUrl")
           .setValue(url!.absoluteString)

let resource = Resource(downloadURL: url!, cacheKey: productImageref)

【问题讨论】:

  • 您是否检查过 URL 是否已被转义? Röda.png 应该在 URL 路径中变为 R%C3%B6da.png
  • @CodeDifferent 实际上在 Firebase 存储中的 URL 路径是 Ro%CC%88da

标签: ios swift firebase firebase-realtime-database firebase-storage


【解决方案1】:

在花费大量时间研究您的问题后,差异归结为字符 ö 的编码方式,我将其追溯到 Unicode 规范化形式。

字母ö可以写成两种方式,String/NSString认为它们相等:

let str1 = "o\u{308}" // decomposed : latin small letter o + combining diaeresis
let str2 = "\u{f6}"   // precomposed: latin small letter o with diaeresis

print(str1, str2, str1 == str2) // ö ö true

但是当你对它们进行百分比编码时,它们会产生不同的结果:

print(str1.stringByAddingPercentEncodingWithAllowedCharacters(.URLPathAllowedCharacterSet())!)
print(str2.stringByAddingPercentEncodingWithAllowedCharacters(.URLPathAllowedCharacterSet())!)

// o%CC%88
// %C3%B6

我的猜测是 Google / Firebase 选择了分解的形式,而 Apple 在其文本输入系统中更喜欢另一种形式。您可以将文件名转换为其分解形式以匹配 Firebase:

let str3 = str2.decomposedStringWithCanonicalMapping
print(str3.stringByAddingPercentEncodingWithAllowedCharacters(.URLPathAllowedCharacterSet()))

// o%CC%88

这与 ASCII 范围的字符无关。 Unicode 可能非常令人困惑。

参考资料:

【讨论】:

    【解决方案2】:

    Unicode 万岁!

    简短的回答是,不,我们实际上并没有在这里做任何特别的事情。基本上我们在后台所做的就是:

    // This is the list at https://cloud.google.com/storage/docs/json_api/ without the & because query parameters
    NSString *const kGCSObjectAllowedCharacterSet = 
        @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*+,;=:@";
    
    - (nullable NSString *)GCSEscapedString:(NSString *)string {
      NSCharacterSet *allowedCharacters =
          [NSCharacterSet characterSetWithCharactersInString:kGCSObjectAllowedCharacterSet];
    
      return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
    }
    

    让我大吃一惊的是:

    let str1 = "o\u{308}" // decomposed : latin small letter o + combining diaeresis
    let str2 = "\u{f6}"   // precomposed: latin small letter o with diaeresis
    
    print(str1, str2, str1 == str2) // ö ö true
    

    返回true。在 Objective-C(Firebase 存储客户端内置)中,它完全不应该,因为它们是两个完全不同的字符(实际上,str1 的长度是2str2 的长度在 Obj-C 中是 1,而在 Swift 中我假设两者的答案都是 1

    Apple 必须在 Swift 中进行比较之前对字符串进行规范化(这可能是一件合理的事情,否则会导致像 this 这样的错误,其中字符串“相同”但比较不同)。事实证明,这正是他们所做的(参见他们docs 的“扩展字素集群”部分)。

    因此,当您在 Swift 中提供两个不同的字符时,它们将作为不同的字符传播到 Obj-C,因此编码方式也不同。不是错误,只是 Swift 的 String 类型和 Obj-C 的 NSString 类型之间的众多差异之一。如有疑问,请选择您期望的规范表示并坚持使用,但作为库开发人员,我们很难为您选择该表示。

    因此,在命名包含 Unicode 字符的文件时,请确保选择标准表示(C、D、KC 或 KD)并在创建引用时始终使用它。

    let imageName = "smorgasbörd.jpg"
    let path = "images/\(imageName)"
    let decomposedPath = path.decomposedStringWithCanonicalMapping // Unicode Form D
    let ref = FIRStorage.storage().reference().child(decomposedPath)
    // use this ref and you'll always get the same objects
    

    【讨论】:

    • 那么我有哪些选择?据我所知,没有必要再像回答“代码不同”那样做同样的事情,因为你已经在“在你的引擎盖下”这样做了。
    • 您的选择是选择一个 Unicode 规范化(我编辑了我的答案以显示 D),并在所有操作中坚持它。 Swift 和 Objective-C 处理事情的方式不同,所以使用哪一个很重要。复制和粘贴随机 Unicode 字符可能不起作用,因为它们会被区别对待(很可能)。
    • 非常感谢 :) 太混乱了,但现在可以正常工作了。
    • 我只想说这不是问题的终结。使用分解后的路径,这些是唯一不缓存的图像。因此,我想我只需要删除那些。
    猜你喜欢
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 2018-04-01
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多