JKSwiftExtension,测试用例在 StringExtensionViewController 里面
目录:
1、字符串基本的扩展
2、沙盒路径的获取
3、iOS CharacterSet(字符集)
4、字符串的转换
5、字符串UI的处理
6、字符串有关数字方面的扩展
7、苹果针对浮点类型计算精度问题提供出来的计算类
8、字符串包含表情的处理
9、字符串的一些正则校验
10、字符串截取的操作
11、字符串编码的处理
一、字符串基本的扩展
// MARK:- 0:字符串基本的扩展 public extension String { // MARK: 0.1、字符串的长度 /// 字符串的长度 var length: Int { return self.count } // MARK: 0.2、判断是否包含某个子串 /// 判断是否包含某个子串 /// - Parameter find: 子串 /// - Returns: Bool func contains(find: String) -> Bool { return self.range(of: find) != nil } // MARK: 0.3、判断是否包含某个子串 -- 忽略大小写 /// 判断是否包含某个子串 -- 忽略大小写 /// - Parameter find: 子串 /// - Returns: Bool func containsIgnoringCase(find: String) -> Bool { return self.range(of: find, options: .caseInsensitive) != nil } // MARK: 0.4、字符串转 Base64 /// 字符串转 Base64 var base64: String? { guard let plainData = (self as NSString).data(using: String.Encoding.utf8.rawValue) else { return nil } let base64String = plainData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0)) return base64String } // MARK: 0.5、将16进制字符串转为Int /// 将16进制字符串转为Int var hexInt: Int { return Int(self, radix: 16) ?? 0 } // MARK: 0.6、判断是不是九宫格键盘 /// 判断是不是九宫格键盘 func isNineKeyBoard() -> Bool { let other : NSString = "➋➌➍➎➏➐➑➒" let len = self.count for _ in 0..<len { if !(other.range(of: self).location != NSNotFound) { return false } } return true } // MARK: 0.7、字符串转 UIViewController /// 字符串转 UIViewController /// - Returns: 对应的控制器 @discardableResult func toViewController() -> UIViewController? { // 1.动态获取命名空间 let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String // 2.将字符串转换为类 // 2.1.默认情况下命名空间就是项目的名称,但是命名空间的名称是可以更改的 guard let Class: AnyClass = NSClassFromString(namespace + "." + self) else { return nil } // 3.通过类创建对象 // 3.1.将AnyClass 转化为指定的类 let vcClass = Class as! UIViewController.Type // 4.通过class创建对象 let vc = vcClass.init() return vc } // MARK: 0.8、字符串转 AnyClass /// 字符串转 AnyClass /// - Returns: 对应的 Class @discardableResult func toClass() -> AnyClass? { // 1.动态获取命名空间 let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String // 2.将字符串转换为类 // 2.1.默认情况下命名空间就是项目的名称,但是命名空间的名称是可以更改的 guard let Class: AnyClass = NSClassFromString(namespace + "." + self) else { return nil } return Class } }
二、沙盒路径的获取
// MARK:- 1、沙盒路径的获取 /* - 1、Home(应用程序包)目录 - 整个应用程序各文档所在的目录,包含了所有的资源文件和可执行文件 - 2、Documents - 保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录 - 需要保存由"应用程序本身"产生的文件或者数据,例如: 游戏进度,涂鸦软件的绘图 - 目录中的文件会被自动保存在 iCloud - 注意: 不要保存从网络上下载的文件,否则会无法上架! - 3、Library - 3.1、Library/Cache - 保存应用运行时生成的需要持久化的数据,iTunes同步设备时不备份该目录。一般存放体积大、不需要备份的非重要数据 - 保存临时文件,"后续需要使用",例如: 缓存的图片,离线数据(地图数据) - 系统不会清理 cache 目录中的文件 - 就要求程序开发时, "必须提供 cache 目录的清理解决方案" - 3.2、Library/Preference - 保存应用的所有偏好设置,IOS的Settings应用会在该目录中查找应用的设置信息。iTunes - 用户偏好,使用 NSUserDefault 直接读写! - 如果想要数据及时写入硬盘,还需要调用一个同步方法 - 4、tmp - 保存临时文件,"后续不需要使用" - tmp 目录中的文件,系统会自动被清空 - 重新启动手机, tmp 目录会被清空 - 系统磁盘空间不足时,系统也会自动清理 - 保存应用运行时所需要的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行,系统也可能会清除该目录下的文件,iTunes不会同步备份该目录 */ public extension String { // MARK: 1.1、获取Home的完整路径名 /// 获取Home的完整路径名 /// - Returns: Home的完整路径名 static func homeDirectory() -> String { //获取程序的Home目录 let homeDirectory = NSHomeDirectory() return homeDirectory } // MARK: 1.2、获取Documnets的完整路径名 /// 获取Documnets的完整路径名 /// - Returns: Documnets的完整路径名 static func DocumnetsDirectory() -> String { //获取程序的documentPaths目录 //方法1 // let documentPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) // let documnetPath = documentPaths[0] //方法2 let ducumentPath = NSHomeDirectory() + "/Documents" return ducumentPath } // MARK: 1.3、获取Library的完整路径名 /** 这个目录下有两个子目录:Caches 和 Preferences Library/Preferences目录,包含应用程序的偏好设置文件。不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好。 Library/Caches目录,主要存放缓存文件,iTunes不会备份此目录,此目录下文件不会再应用退出时删除 */ /// 获取Library的完整路径名 /// - Returns: Library的完整路径名 static func LibraryDirectory() -> String { //获取程序的documentPaths目录 //Library目录-方法1 // let libraryPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) // let libraryPath = libraryPaths[0] // // Library目录-方法2 let libraryPath = NSHomeDirectory() + "/Library" return libraryPath } // MARK: 1.4、获取/Library/Caches的完整路径名 /// 获取/Library/Caches的完整路径名 /// - Returns: /Library/Caches的完整路径名 static func CachesDirectory() -> String { //获取程序的/Library/Caches目录 let cachesPath = NSHomeDirectory() + "/Library/Caches" return cachesPath } // MARK: 1.5、获取Library/Preferences的完整路径名 /// 获取Library/Preferences的完整路径名 /// - Returns: Library/Preferences的完整路径名 static func PreferencesDirectory() -> String { //Library/Preferences目录-方法2 let preferencesPath = NSHomeDirectory() + "/Library/Preferences" return preferencesPath } // MARK: 1.6、获取Tmp的完整路径名 /// 获取Tmp的完整路径名,用于存放临时文件,保存应用程序再次启动过程中不需要的信息,重启后清空。 /// - Returns: Tmp的完整路径名 static func TmpDirectory() -> String { //方法1 //let tmpDir = NSTemporaryDirectory() //方法2 let tmpDir = NSHomeDirectory() + "/tmp" return tmpDir } }
三、iOS CharacterSet(字符集)
// MARK:- 二、iOS CharacterSet(字符集) /** CharacterSet是在Foundation框架下的一个结构体,用于搜索操作的一组Unicode字符值。官方的API地址:https://developer.apple.com/documentation/foundation/characterset 概述 字符集表示一组符合unicode的字符。基础类型使用字符集将字符组合在一起进行搜索操作,以便在搜索期间可以找到任何特定的字符集。 这种类型提供了“写时复制”的行为,并且还连接到Objective-C NSCharacterSet类。 总之就是将unicode字符,按组分类,便于搜索查找,验证字符串。通常我们在一些场景下会用到一个字符串是否包含某种特定字符,比如判断密码是否只包含数字,检查url是否有不规范字符,删除多余空格等操作 属性 描述 CharacterSet.alphanumerics controlCharacters: 控制符 whitespaces: 空格 whitespacesAndNewlines: 空格和换行 decimalDigits: 0-9的数字,也不包含小数点 letters: 所有英文字母,包含大小写 65-90 97-122 lowercaseLetters: 小写英文字母 97-122 uppercaseLetters: 大写英文字母 65-90 nonBaseCharacters: 非基础字符 M* alphanumerics: 字母和数字的组合,包含大小写, 不包含小数点 decomposables: 可分解 illegalCharacters: 不合规字符,没有在Unicode 3.2 标准中定义的字符 punctuationCharacters: 标点符号,连接线,引号什么的 P* capitalizedLetters: 字母,首字母大写,Lt类别 symbols: 符号,包含S* 所有内容,运算符,货币符号什么的 newlines: 返回一个包含换行符的字符集,U+000A ~ U+000D, U+0085, U+2028, and U+2029 urlUserAllowed: urlPasswordAllowed: urlHostAllowed: urlPathAllowed: urlQueryAllowed: urlFragmentAllowed: bitmapRepresentation: inverted: 相反的字符集。例如 CharacterSet.whitespaces.inverted 就是没有空格 */ public extension String { // MARK: 2.1、去除字符串前后的 空格 /// 去除字符串前后的换行和换行 var removeBeginEndAllSapcefeed: String { let resultString = self.trimmingCharacters(in: CharacterSet.whitespaces) return resultString } // MARK: 2.2、去除字符串前后的 换行 /// 去除字符串前后的 换行 var removeBeginEndAllLinefeed: String { let resultString = self.trimmingCharacters(in: CharacterSet.newlines) return resultString } // MARK: 2.3、去除字符串前后的 换行和空格 /// 去除字符串前后的 换行和空格 var removeBeginEndAllSapceAndLinefeed: String { var resultString = self.trimmingCharacters(in: CharacterSet.whitespaces) resultString = resultString.trimmingCharacters(in: CharacterSet.newlines) return resultString } // MARK: 2.4、去掉所有空格 /// 去掉所有空格 var removeAllSapce: String { return replacingOccurrences(of: " ", with: "", options: .literal, range: nil) } // MARK: 2.5、去掉所有换行 /// 去掉所有换行 var removeAllLinefeed: String { return replacingOccurrences(of: "\n", with: "", options: .literal, range: nil) } // MARK: 2.6、去掉所有空格 和 换行 /// 去掉所有的空格 和 换行 var removeAllLineAndSapcefeed: String { // 去除所有的空格 var resultString = replacingOccurrences(of: " ", with: "", options: .literal, range: nil) // 去除所有的换行 resultString = resultString.replacingOccurrences(of: "\n", with: "", options: .literal, range: nil) return resultString } // MARK: 2.7、是否是 0-9 的数字,也不包含小数点 /// 是否是 0-9 的数字,也不包含小数点 /// - Returns: 结果 func isValidNumber() -> Bool { /// 0-9的数字,也不包含小数点 let rst: String = self.trimmingCharacters(in: .decimalDigits) if rst.count > 0 { return false } return true } // MARK: 2.8、url进行编码 /// url 进行编码 /// - Returns: 返回对应的URL func urlValidate() -> URL { return URL(string: self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed) ?? "")! } // MARK: 2.9、某个字符使用某个字符替换掉 /// 某个字符使用某个字符替换掉 /// - Parameters: /// - removeString: 原始字符 /// - replacingString: 替换后的字符 /// - Returns: 替换后的整体字符串 func removeSomeStringUseSomeString(removeString: String, replacingString: String = "") -> String { return replacingOccurrences(of: removeString, with: replacingString) } // MARK: 2.10、使用正则表达式替换某些子串 /// 使用正则表达式替换 /// - Parameters: /// - pattern: 正则 /// - with: 用来替换的字符串 /// - options: 策略 /// - Returns: 返回替换后的字符串 func pregReplace(pattern: String, with: String, options: NSRegularExpression.Options = []) -> String { let regex = try! NSRegularExpression(pattern: pattern, options: options) return regex.stringByReplacingMatches(in: self, options: [], range: NSMakeRange(0, self.count), withTemplate: with) } // MARK: 2.11、删除指定的字符 /// 删除指定的字符 /// - Parameter characterString: 指定的字符 /// - Returns: 返回删除后的字符 func removeCharacter(characterString: String) -> String { let characterSet = CharacterSet(charactersIn: characterString) return trimmingCharacters(in: characterSet) } }
四、字符串的转换
// MARK:- 三、字符串的转换 public extension String { // MARK: 3.1、字符串 转 CGFloat /// 字符串 转 Float /// - Returns: CGFloat func toCGFloat() -> CGFloat? { if let doubleValue = Double(self) { return CGFloat(doubleValue) } return nil } // MARK: 3.2、字符串转 bool /// 字符串转 bool var bool: Bool? { switch self.lowercased() { case "true", "t", "yes", "y", "1": return true case "false", "f", "no", "n", "0": return false default: return nil } } // MARK: 3.3、字符串转 Int /// 字符串转 Int /// - Returns: Int func toInt() -> Int? { if let num = NumberFormatter().number(from: self) { return num.intValue } else { return nil } } // MARK: 3.4、字符串转 Double /// 字符串转 Double /// - Returns: Double func toDouble() -> Double? { if let num = NumberFormatter().number(from: self) { return num.doubleValue } else { return nil } } // MARK: 3.5、字符串转 Float /// 字符串转 Float /// - Returns: Float func toFloat() -> Float? { if let num = NumberFormatter().number(from: self) { return num.floatValue } else { return nil } } // MARK: 3.6、字符串转 Bool /// 字符串转 Bool /// - Returns: Bool func toBool() -> Bool? { let trimmedString = lowercased() if trimmedString == "true" || trimmedString == "false" { return (trimmedString as NSString).boolValue } return nil } // MARK: 3.7、字符串转 NSString /// 字符串转 NSString var toNSString: NSString { return self as NSString } }
五、字符串UI的处理
// MARK:- 四、字符串UI的处理 extension String { // MARK: 4.1、对字符串(多行)指定出字体大小和最大的 Size,获取 (Size) /// 对字符串(多行)指定出字体大小和最大的 Size,获取展示的 Size /// - Parameters: /// - font: 字体大小 /// - size: 字符串的最大宽和高 /// - Returns: 按照 font 和 Size 的字符的Size public func rectSize(font: UIFont, size: CGSize) -> CGSize { let attributes = [NSAttributedString.Key.font: font] /** usesLineFragmentOrigin: 整个文本将以每行组成的矩形为单位计算整个文本的尺寸 usesFontLeading: usesDeviceMetrics: @available(iOS 6.0, *) truncatesLastVisibleLine: */ let option = NSStringDrawingOptions.usesLineFragmentOrigin let rect: CGRect = self.boundingRect(with: size, options: option, attributes: attributes, context: nil) return rect.size } // MARK: 4.2、对字符串(多行)指定字体及Size,获取 (高度) /// 对字符串指定字体及Size,获取 (高度) /// - Parameters: /// - font: 字体的大小 /// - size: 字体的size /// - Returns: 返回对应字符串的高度 public func rectHeight(font: UIFont, size: CGSize) -> CGFloat { return rectSize(font: font, size: size).height } // MARK: 4.3、对字符串(多行)指定字体及Size,获取 (宽度) /// 对字符串指定字体及Size,获取 (宽度) /// - Parameters: /// - font: 字体的大小 /// - size: 字体的size /// - Returns: 返回对应字符串的宽度 public func rectWidth(font: UIFont, size: CGSize) -> CGFloat { return rectSize(font: font, size: size).width } // MARK: 4.4、对字符串(单行)指定字体,获取 (Size) /// 对字符串(单行)指定字体,获取 (Size) /// - Parameter font: 字体的大小 /// - Returns: 返回单行字符串的 size public func singleLineSize(font: UIFont) -> CGSize { let attrs = [NSAttributedString.Key.font: font] return self.size(withAttributes: attrs as [NSAttributedString.Key: Any]) } // MARK: 4.5、对字符串(单行)指定字体,获取 (width) /// 对字符串(单行)指定字体,获取 (width) /// - Parameter font: 字体的大小 /// - Returns: 返回单行字符串的 width public func singleLineWidth(font: UIFont) -> CGFloat { let attrs = [NSAttributedString.Key.font: font] return self.size(withAttributes: attrs as [NSAttributedString.Key: Any]).width } // MARK: 4.6、对字符串(单行)指定字体,获取 (Height) /// 对字符串(单行)指定字体,获取 (height) /// - Parameter font: 字体的大小 /// - Returns: 返回单行字符串的 height public func singleLineHeight(font: UIFont) -> CGFloat { let attrs = [NSAttributedString.Key.font: font] return self.size(withAttributes: attrs as [NSAttributedString.Key: Any]).height } // MARK: 4.7、字符串通过 label 根据高度&字体 —> Size /// 字符串通过 label 根据高度&字体 ——> Size /// - Parameters: /// - height: 字符串最大的高度 /// - font: 字体大小 /// - Returns: 返回Size public func sizeAccording(width: CGFloat, height: CGFloat = CGFloat(MAXFLOAT), font: UIFont) -> CGSize { if self.isBlank {return CGSize(width: 0, height: 0)} let rect = CGRect(x: 0, y: 0, width: width, height: height) let label = UILabel(frame: rect).font(font).text(self).line(0) return label.sizeThatFits(rect.size) } // MARK: 4.8、字符串通过 label 根据高度&字体 —> Width /// 字符串通过 label 根据高度&字体 ——> Width /// - Parameters: /// - height: 字符串最大高度 /// - font: 字体大小 /// - Returns: 返回宽度大小 public func widthAccording(width: CGFloat, height: CGFloat = CGFloat(MAXFLOAT), font: UIFont) -> CGFloat { if self.isBlank {return 0} let rect = CGRect(x: 0, y: 0, width: width, height: height) let label = UILabel(frame: rect).font(font).text(self).line(0) return label.sizeThatFits(rect.size).width } // MARK: 4.9、字符串通过 label 根据宽度&字体 —> height /// 字符串通过 label 根据宽度&字体 ——> height /// - Parameters: /// - width: 字符串最大宽度 /// - font: 字体大小 /// - Returns: 返回高度大小 public func heightAccording(width: CGFloat, height: CGFloat = CGFloat(MAXFLOAT), font: UIFont) -> CGFloat { if self.isBlank {return 0} let rect = CGRect(x: 0, y: 0, width: width, height: height) let label = UILabel(frame: rect).font(font).text(self).line(0) return label.sizeThatFits(rect.size).height } // MARK: 4.10、字符串根据宽度 & 字体 & 行间距 —> Size /// 字符串根据宽度 & 字体 & 行间距 ——> Size /// - Parameters: /// - width: 字符串最大的宽度 /// - heiht: 字符串最大的高度 /// - font: 字体的大小 /// - lineSpacing: 行间距 /// - Returns: 返回对应的size public func sizeAccording(width: CGFloat, height: CGFloat = CGFloat(MAXFLOAT), font: UIFont, lineSpacing: CGFloat) -> CGSize { if self.isBlank {return CGSize(width: 0, height: 0)} let rect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT)) let label = UILabel(frame: rect).font(font).text(self).line(0) let attrStr = NSMutableAttributedString(string: self) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineSpacing attrStr.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, self.count)) label.attributedText = attrStr return label.sizeThatFits(rect.size) } // MARK: 4.11、字符串根据宽度 & 字体 & 行间距 —> width /// 字符串根据宽度 & 字体 & 行间距 ——> width /// - Parameters: /// - width: 字符串最大的宽度 /// - heiht: 字符串最大的高度 /// - font: 字体的大小 /// - lineSpacing: 行间距 /// - Returns: 返回对应的 width public func widthAccording(width: CGFloat, height: CGFloat = CGFloat(MAXFLOAT), font: UIFont, lineSpacing: CGFloat) -> CGFloat { if self.isBlank {return 0} let rect = CGRect(x: 0, y: 0, width: width, height: height) let label = UILabel(frame: rect).font(font).text(self).line(0) let attrStr = NSMutableAttributedString(string: self) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineSpacing attrStr.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, self.count)) label.attributedText = attrStr return label.sizeThatFits(rect.size).width } // MARK: 4.12、字符串根据宽度 & 字体 & 行间距 —> height /// 字符串根据宽度 & 字体 & 行间距 ——> height /// - Parameters: /// - width: 字符串最大的宽度 /// - heiht: 字符串最大的高度 /// - font: 字体的大小 /// - lineSpacing: 行间距 /// - Returns: 返回对应的 height public func heightAccording(width: CGFloat, height: CGFloat = CGFloat(MAXFLOAT), font: UIFont, lineSpacing: CGFloat) -> CGFloat { if self.isBlank {return 0} let rect = CGRect(x: 0, y: 0, width: width, height: height) let label = UILabel(frame: rect).font(font).text(self).line(0) let attrStr = NSMutableAttributedString(string: self) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineSpacing attrStr.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, self.count)) label.attributedText = attrStr return label.sizeThatFits(rect.size).height } }