从 FengNiao 中学习 Swift (三)

2017-12-11  本文已影响88人  要上班的斌哥

从 FengNiao 中学习 Swift (一) 中介绍了 Swift Package Manager 的基本用法,然后创建了FengNiaoCopy 项目。
从 FengNiao 中学习 Swift (二) 中主要介绍如何处理命令行的输入参数。
接下来的这个文章主要介绍 FengNiao 的字符串搜索规则,通过这个规则来介绍 Swift 的 protocol 和 extension。

搜索

FengNiao 的搜索功能是在所有的搜索文件中寻找字符串,这些文件后缀可能是 swift,m,mm,xib,storyboard 等,若是字符串存在图片后缀名,那么将这个图片后缀名去除。

protocol

在 swift 中定义协议使用关键字 protocol,可以在 protocol 里面声明方法, 这点和 Objective-C 一样。

// 定义协议
protocol FileSearchRule {
    func search(in content : String) -> Set<String>
}

RegPatternSearchRule 协议继承了 FileSearchRule 协议,并添加了 2 个 属性声明

// 协议继承
protocol RegPatternSearchRule : FileSearchRule {
    var extensions:[String] { get }
    var patterns:[String] { get }
}

在 FengNiao 中,我们需要从 swift,m,mm,xib,storyboard等文件类型中来进行搜索,从功能设计的角度来说,我们只是要进行 “字符串搜索”,但是需要搜索不同类型的文件,所以我们定义了一个具备基本搜索功能的协议 RegPatternSearchRule,不同类型文件的搜索规则只要继承 RegPatternSearchRule 协议,并提供该类型文件的搜索正则表达式即可。

// 用于 ObjC 类型文件的字符串搜索
struct ObjCImageSearchRule : RegPatternSearchRule {
    let extensions: [String]
    // 匹配任意字符串 @""  ""
    let patterns = ["@\"(.*?)\"", "\"(.*?)\""]
}

// 用于 Swift 类型文件的字符串搜索
struct SwiftImageSearchRule : RegPatternSearchRule {
    let  extensions: [String]
    // 匹配任意字符串 ""
    let patterns = ["\"(.*?)\""]
}

// 用于 xib storyboard 的字符串搜索
struct XibImageSearchRule : RegPatternSearchRule {
    let extensions =  [String]()
    // .xib 字符串 image=""
    let patterns = ["image name=\"(.*?)\"", "image=\"(.*?)\"", "value=\"(.*?)\""]
}

// 用于 plist 的字符串搜索
struct PlistImageSearchRule :RegPatternSearchRule {
    let extensions =  [String]()
    let patterns = ["<key>UIApplicationShortcutItemIconFile</key>[^<]*<string>(.*?)</string>"]
}

// 用于普通文件的字符串搜索
struct PlainImageSearchRule : RegPatternSearchRule {
    let extensions: [String]
    var patterns: [String] {
        if extensions.isEmpty {
            return []
        }
        
        let joinedExt = extensions.joined(separator: "|")
        return ["\"(.+?)\\.(\(joinedExt))\""]
    }
}

extension

在 swift 中 protocol 也是可以 extension 的,这个 extension 类似 Objective-C 的 category 功能。
前面提到的 FileSearchRule 协议定义搜索方法,RegPatternSearchRule 继承 FileSearchRule 并添加 extensions 和 patterns 属性,patterns 属性用来保存搜索的正则表达式。FileSearchRule 协议中定义的方法要在什么地方来实现呢?在这里我们选择在 RegPatternSearchRule 的 extension 里面实现。

// 拓展协议
extension RegPatternSearchRule{
    // 查找文件名
    func search(in content :String) -> Set<String>{
        let nsstring = NSString(string:content)
        var result = Set<String>()
        for pattern in patterns {
            // 正则匹配
            let reg = try! NSRegularExpression(pattern: pattern, options: .caseInsensitive)
            let matches = reg.matches(in: content, options: [], range: content.fullRange)
            for checkingResult in matches {
                let extracted = nsstring.substring(with: checkingResult.rangeAt(1))
                result.insert(extracted.plainFileName(extensions: extensions))
            }
        }
        return result;
    }
}

除了给 protocol 添加 extension,我们也可以给系统的类添加 extension,这一点和 Objective-C 是一致的。比如我们给 String 类型添加一个 fullRange 属性和 plainFileName 方法。

import Foundation
import PathKit

extension String{
    var fullRange:NSRange{
        let nsstring = NSString(string: self)
        return NSMakeRange(0, nsstring.length)
    }
    
    func plainFileName(extensions:[String]) -> String{
        let p = Path(self)
        var result : String!
        for ext in extensions {
            if hasSuffix(".\(ext)"){
                result = p.lastComponentWithoutExtension
                break
            }
        }
        
        if result == nil {
            result = p.lastComponent
        }
        
        if result.hasSuffix("@2x") || result.hasSuffix("@3x") {
            let endIndex = result.index(result.endIndex, offsetBy: -3)
            result = result.substring(to: endIndex);
        }
        return result
    }

}
上一篇下一篇

猜你喜欢

热点阅读