在 从 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
}
}
网友评论