美文网首页iOSSwift学习swift
[iOS][Swift]字符串查找所有子串及Range转换成NS

[iOS][Swift]字符串查找所有子串及Range转换成NS

作者: 囧书 | 来源:发表于2017-08-10 15:54 被阅读504次

    从Swift字符串中查找给定子串的所有Range

    使用到一个关键的方法:

    range(of: string, options: , range: , locale: )
    

    这个方法在给定给定范围内查找子串,并在查到第一个子串时返回Range类型的结果。

    如此一来,我们只需要不断改变查找范围,把每一次查找得到的Range都记录下来,最终就能得到所有Range。

    1、初始化时先设置查找范围为整个字符串
    2、若能通过查找得到子串的Range,进入循环
    3、保存子串Range到数组
    4、缩小查找范围,减掉已经查找过的区域
    5、在缩小的范围内查找子串
    6、若能在缩小的范围内找到子串,继续下一轮循环

    extension String {
        func ranges(of string: String) -> [Range<String.Index>] {
            var rangeArray = [Range<String.Index>]()
            var searchedRange: Range<String.Index>
            guard let sr = self.range(of: self) else {
                return rangeArray
            }
            searchedRange = sr
            
            var resultRange = self.range(of: string, options: .regularExpression, range: searchedRange, locale: nil)
            while let range = resultRange {
                rangeArray.append(range)
                searchedRange = Range(uncheckedBounds: (range.upperBound, searchedRange.upperBound))
                resultRange = self.range(of: string, options: .regularExpression, range: searchedRange, locale: nil)
            }
            return rangeArray
        }
    }
    

    把Range转换成NSRange

    Swift3的转换方法:

    OC常用的NSRange不依赖于任何类型,独立成型,要创建一个NSRange只需要给出区间起始点,以及区间长度即可,而这两个值都是整型。

    NSMakeRange(3, 5)
    

    但是Swift新增的Range类型,是建立在其它类型的基础上,是对其它类型的描述。
    在本文,Range通过range(of string)而取得,依赖于String。要把它转换成独立的NSRange,需要分别对其lowerBoundupperBound通过String.UTF16View来转换成整型。

    extension String {
        func nsrange(fromRange range : Range<String.Index>) -> NSRange {
            let utf16view = self.utf16
            let from = String.UTF16View.Index(range.lowerBound, within: utf16view)
            let to = String.UTF16View.Index(range.upperBound, within: utf16view)
            return NSMakeRange(utf16view.startIndex.distance(to: from), from.distance(to: to))
        }
    }
    

    Swift4的转换方法:

    苹果在Swift4对字符串作了很大改动,字符串变回了集合类型,相应地其很多api都发生了变化,这是题外话了...
    在Swift4,苹果增加了api直接支持把Range转换成NSRange,它是NSRange的构造方法:

    NSRange(range, in: string)
    

    给构造方法传入range以及这个range相应的string即可。
    所以到了Swift4,把方法重构一下,只需要一行代码:

    extension String {
        func nsrange(fromRange range : Range<String.Index>) -> NSRange {
            return NSRange(range, in: self)
        }
    }
    

    此时可以顺便添加一个方法,在String中查找子串,返回NSRange数组:

    extension String {
        func nsranges(of string: String) -> [NSRange] {
            return ranges(of: string).map { (range) -> NSRange in
                self.nsrange(fromRange: range)
            }
        }
    }
    

    测试一下

    let text = "😊连续的降雨把佛罗里达州的迈阿卡河州立公园变成了一个水世界。迈阿卡河州立公园😊是佛罗里达最古老、最大型的公园之一😊,绵延3.7万英亩。这里有各种各样的自然特征,包括一片森林湿地,也叫做沼泽生态系统💐,是由各种各样的树木组成的一种美妙的自然生态系统。"
    
    let ranges = text.ranges(of: "😊")
    print("------ ranges of 😊 :\(ranges.count) ------")
    dump(ranges)
    
    let nsranges = text.nsranges(of: "😊")
    print("------ nsranges of 😊 :\(nsranges.count) ------")
    dump(nsranges)
    
    swift3运行结果 swift4的NSRange

    查看完整项目

    GitHub:StringRange

    相关文章

      网友评论

      • 游龙飞雪:这样子确实能得到结果。但实在搞不懂,在Swift中费了这么大的力气找到range<String.Index>,还要再转成NSRange…… 那还不如先把string转成nsString,直接使用oc的操作得到nsrange :cry:
        囧书:@游龙飞雪 好赞,谢谢
        游龙飞雪:@梁炯幸 :joy: 我觉得是咱们API没找对,我刚找到一种方法,分享下,如下:

        let str: String = "我最爱北京天安门!"
        let range: Range = str.range(of: "北京")!
        let location: Int = str.distance(from: str.startIndex, to: range.lowerBound)
        /* location = 3 */

        let keyLength: Int = str.distance(from: range.lowerBound, to: range.upperBound)
        // let key = "北京"; let keyLength = key.count //count = 2
        /* keyLength = 2 */

        print("location = \(location), length = \(keyLength)")
        /* location = 3, length = 2 */

      本文标题:[iOS][Swift]字符串查找所有子串及Range转换成NS

      本文链接:https://www.haomeiwen.com/subject/nkpqrxtx.html