Swift5中String.count 与 NSString.length不相等

Swift5中String.count 与 NSString.length不相等

问题描述

  • 在我对微博国际版的Text显示框架进行重构的时候,发现了会有部分在末尾的文字内容无法解析成对应的样式。

梳理后发现了这样的问题:

    let topicRegex: NSRegularExpression? = try? NSRegularExpression(pattern: "#[^#']+#", options: .caseInsensitive)
    let str = "文本文本文本文本文本文本文本文本#话题1##话题2##话题3##话题4##话题5##话题6##话题7##话题8##话题9#"
    func topicRegexHasEmojTest() {
        if let results = topicRegex?.matches(in: str, options: [], range: NSRange(location: 0, length: str.count)) {
            var resultStrs = ""
            for result in results {
                resultStrs.append(NSString(string: str).substring(with: result.range))
            }
            print("1:"+resultStrs)
            print("----------")
        }
    }

代码打印结果为:
1:#话题1##话题2##话题3##话题4##话题5##话题6#
而最末尾的#话题7##话题8##话题9#没有被成功解析,如果把文本中的emoj删除,则有可以搜索到所有字符,这里我意识到,可能是正则寻找的count出现了问题。

  • 于是我做了下面的测试:
let str1 = "❤️❤️"
let str2 = NSString(string: str1)
print("str1.count = \(str1.count), str2.length = \(str2.length)")
//str1.count = 4, str2.length = 8

  • 实锤了,swift.count跟NSString.length的确不是一个玩意,尤其在emoj上,一个emoj表情占的明显比一个汉字要多。
  • 问题发现了,但是解决时候其实有点困难,因为在网上没有搜索到明显关于这方面的解答。不过运气不错的是,我在看Swift的String注释文档时候,看到了这样的内容:
/// The UTF-16 code units of a string's `utf16` view match the elements
     /// accessed through indexed `NSString` APIs.
     ///
     ///     print(flowers.utf16.count)
     ///     // Prints "10"
     ///
     ///     let nsflowers = flowers as NSString
     ///     print(nsflowers.length)
     ///     // Prints "10"
     ///
     /// Unlike `NSString`, however, `String.UTF16View` does not use integer
     /// indices. If you need to access a specific position in a UTF-16 view, use
     /// Swift's index manipulation methods. The following example accesses the
     /// fourth code unit in both the `flowers` and `nsflowers` strings:
  • 所以就是说,swift中String如果用str.utf16.count 那么就可以等于NSString.length吧,说没用,试试:
let str1 = "❤️❤️"
let str2 = NSString(string: str1)
print("str1.count = \(str1.count), str1.utf16.count = \(str1.utf16.count), str2.length = \(str2.length)")
str1.count = 4, str1.utf16.count = 8, str2.length = 8

问题解决

当我用str.utf16.count 时候,就可以得到和NSString一样的长度了。

    func topicRegexHas2EmojTest() {
        if let results = topicRegex?.matches(in: str, options: [], range: NSRange(location: 0, length: str.utf16.count)) {
            var resultStrs = ""
            for result in results {
                resultStrs.append(NSString(string: str).substring(with: result.range))
            }
            print("2:"+resultStrs)
            print("----------")
        }
    }

//2:#话题1##话题2##话题3##话题4##话题5##话题6##话题7##话题8##话题9#
//----------

ps

有兴趣的其实可以打印一下这个

你可能感兴趣的:(Swift5中String.count 与 NSString.length不相等)