Swift:String+Extension

JKSwiftExtension磷杏,測試用例在 StringExtensionViewController 里面
目錄:
1、字符串基本的擴展
2帜慢、沙盒路徑的獲取
3、iOS CharacterSet(字符集)
4、字符串的轉(zhuǎn)換
5、字符串UI的處理
6膛堤、字符串有關(guān)數(shù)字方面的擴展
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淀散、字符串轉(zhuǎn) Base64
   /// 字符串轉(zhuǎn) 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進制字符串轉(zhuǎn)為Int
   /// 將16進制字符串轉(zhuǎn)為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档插、字符串轉(zhuǎn) UIViewController
   /// 字符串轉(zhuǎn) UIViewController
   /// - Returns: 對應(yīng)的控制器
   @discardableResult
   func toViewController() -> UIViewController? {
       // 1.動態(tài)獲取命名空間
       let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
       // 2.將字符串轉(zhuǎn)換為類
       // 2.1.默認(rèn)情況下命名空間就是項目的名稱慢蜓,但是命名空間的名稱是可以更改的
       guard let Class: AnyClass = NSClassFromString(namespace + "." + self) else {
           return nil
       }
       // 3.通過類創(chuàng)建對象
       // 3.1.將AnyClass 轉(zhuǎn)化為指定的類
       let vcClass = Class as! UIViewController.Type
       // 4.通過class創(chuàng)建對象
       let vc = vcClass.init()
       return vc
   }

   // MARK: 0.8、字符串轉(zhuǎn) AnyClass
   /// 字符串轉(zhuǎn) AnyClass
   /// - Returns: 對應(yīng)的 Class
   @discardableResult
   func toClass() -> AnyClass? {
       // 1.動態(tài)獲取命名空間
       let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
       // 2.將字符串轉(zhuǎn)換為類
       // 2.1.默認(rèn)情況下命名空間就是項目的名稱郭膛,但是命名空間的名稱是可以更改的
       guard let Class: AnyClass = NSClassFromString(namespace + "." + self) else {
           return nil
       }
       return Class
   }
}

二晨抡、沙盒路徑的獲取

// MARK:- 1、沙盒路徑的獲取
/*
  - 1、Home(應(yīng)用程序包)目錄
  - 整個應(yīng)用程序各文檔所在的目錄,包含了所有的資源文件和可執(zhí)行文件
  - 2耘柱、Documents
  - 保存應(yīng)用運行時生成的需要持久化的數(shù)據(jù)如捅,iTunes同步設(shè)備時會備份該目錄
  - 需要保存由"應(yīng)用程序本身"產(chǎn)生的文件或者數(shù)據(jù),例如: 游戲進度调煎,涂鴉軟件的繪圖
  - 目錄中的文件會被自動保存在 iCloud
  - 注意: 不要保存從網(wǎng)絡(luò)上下載的文件镜遣,否則會無法上架!
  - 3、Library
  - 3.1士袄、Library/Cache
  -  保存應(yīng)用運行時生成的需要持久化的數(shù)據(jù)烈涮,iTunes同步設(shè)備時不備份該目錄。一般存放體積大窖剑、不需要備份的非重要數(shù)據(jù)
  - 保存臨時文件,"后續(xù)需要使用"坚洽,例如: 緩存的圖片,離線數(shù)據(jù)(地圖數(shù)據(jù))
  - 系統(tǒng)不會清理 cache 目錄中的文件
  - 就要求程序開發(fā)時, "必須提供 cache 目錄的清理解決方案"
  - 3.2西土、Library/Preference
  - 保存應(yīng)用的所有偏好設(shè)置讶舰,IOS的Settings應(yīng)用會在該目錄中查找應(yīng)用的設(shè)置信息。iTunes
  - 用戶偏好需了,使用 NSUserDefault 直接讀寫跳昼!
  - 如果想要數(shù)據(jù)及時寫入硬盤,還需要調(diào)用一個同步方法
  - 4肋乍、tmp
  - 保存臨時文件鹅颊,"后續(xù)不需要使用"
  - tmp 目錄中的文件,系統(tǒng)會自動被清空
  - 重新啟動手機, tmp 目錄會被清空
  - 系統(tǒng)磁盤空間不足時墓造,系統(tǒng)也會自動清理
  - 保存應(yīng)用運行時所需要的臨時數(shù)據(jù)堪伍,使用完畢后再將相應(yīng)的文件從該目錄刪除。應(yīng)用沒有運行觅闽,系統(tǒng)也可能會清除該目錄下的文件帝雇,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目錄,包含應(yīng)用程序的偏好設(shè)置文件孕锄。不應(yīng)該直接創(chuàng)建偏好設(shè)置文件吮廉,而是應(yīng)該使用NSUserDefaults類來取得和設(shè)置應(yīng)用程序的偏好。
     Library/Caches目錄畸肆,主要存放緩存文件宦芦,iTunes不會備份此目錄,此目錄下文件不會再應(yīng)用退出時刪除
     */
    /// 獲取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的完整路徑名,用于存放臨時文件令野,保存應(yīng)用程序再次啟動過程中不需要的信息舀患,重啟后清空。
    /// - Returns: Tmp的完整路徑名
    static func TmpDirectory() -> String {
        //方法1
        //let tmpDir = NSTemporaryDirectory()
        //方法2
        let tmpDir = NSHomeDirectory() + "/tmp"
        return tmpDir
    }
}

三气破、iOS CharacterSet(字符集)

// MARK:- 二聊浅、iOS CharacterSet(字符集)
/**
 CharacterSet是在Foundation框架下的一個結(jié)構(gòu)體,用于搜索操作的一組Unicode字符值现使。官方的API地址:https://developer.apple.com/documentation/foundation/characterset
 概述
 字符集表示一組符合unicode的字符低匙。基礎(chǔ)類型使用字符集將字符組合在一起進行搜索操作碳锈,以便在搜索期間可以找到任何特定的字符集顽冶。
 這種類型提供了“寫時復(fù)制”的行為,并且還連接到Objective-C NSCharacterSet類售碳。
 總之就是將unicode字符强重,按組分類,便于搜索查找贸人,驗證字符串间景。通常我們在一些場景下會用到一個字符串是否包含某種特定字符,比如判斷密碼是否只包含數(shù)字艺智,檢查url是否有不規(guī)范字符倘要,刪除多余空格等操作

 屬性                                    描述
 CharacterSet.alphanumerics

 controlCharacters:                     控制符
 whitespaces:                           空格
 whitespacesAndNewlines:                空格和換行
 decimalDigits:                         0-9的數(shù)字,也不包含小數(shù)點
 letters:                               所有英文字母十拣,包含大小寫 65-90 97-122
 lowercaseLetters:                      小寫英文字母 97-122
 uppercaseLetters:                      大寫英文字母 65-90
 nonBaseCharacters:                     非基礎(chǔ)字符 M*
 alphanumerics:                         字母和數(shù)字的組合封拧,包含大小寫, 不包含小數(shù)點
 decomposables:                         可分解
 illegalCharacters:                     不合規(guī)字符,沒有在Unicode 3.2 標(biāo)準(zhǔn)中定義的字符
 punctuationCharacters:                 標(biāo)點符號父晶,連接線哮缺,引號什么的 P*
 capitalizedLetters:                    字母,首字母大寫甲喝,Lt類別
 symbols:                               符號,包含S* 所有內(nèi)容铛只,運算符埠胖,貨幣符號什么的
 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 的數(shù)字锤悄,也不包含小數(shù)點
    /// 是否是 0-9 的數(shù)字,也不包含小數(shù)點
    /// - Returns: 結(jié)果
    func isValidNumber() -> Bool {
        /// 0-9的數(shù)字嘉抒,也不包含小數(shù)點
        let rst: String = self.trimmingCharacters(in: .decimalDigits)
        if rst.count > 0 {
            return false
        }
        return true
    }

    // MARK: 2.8零聚、url進行編碼
    /// url 進行編碼
    /// - Returns: 返回對應(yīng)的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)
    }
}

四、字符串的轉(zhuǎn)換

// MARK:- 三岗宣、字符串的轉(zhuǎn)換
public extension String {

    // MARK: 3.1蚂会、字符串 轉(zhuǎn) CGFloat
    /// 字符串 轉(zhuǎn) Float
    /// - Returns: CGFloat
    func toCGFloat() -> CGFloat? {
        if let doubleValue = Double(self) {
            return CGFloat(doubleValue)
        }
        return nil
    }

    // MARK: 3.2、字符串轉(zhuǎn) bool
    /// 字符串轉(zhuǎn) 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耗式、字符串轉(zhuǎn) Int
    /// 字符串轉(zhuǎn) Int
    /// - Returns: Int
    func toInt() -> Int? {
        if let num = NumberFormatter().number(from: self) {
            return num.intValue
        } else {
            return nil
        }
    }

    // MARK: 3.4颂龙、字符串轉(zhuǎn) Double
    /// 字符串轉(zhuǎn) Double
    /// - Returns: Double
    func toDouble() -> Double? {
        if let num = NumberFormatter().number(from: self) {
            return num.doubleValue
        } else {
            return nil
       }
    }

    // MARK: 3.5、字符串轉(zhuǎn) Float
    /// 字符串轉(zhuǎn) Float
    /// - Returns: Float
    func toFloat() -> Float? {
        if let num = NumberFormatter().number(from: self) {
            return num.floatValue
        } else {
            return nil
        }
    }

    // MARK: 3.6纽什、字符串轉(zhuǎn) Bool
    /// 字符串轉(zhuǎn) Bool
    /// - Returns: Bool
    func toBool() -> Bool? {
        let trimmedString = lowercased()
        if trimmedString == "true" || trimmedString == "false" {
            return (trimmedString as NSString).boolValue
        }
        return nil
    }

    // MARK: 3.7措嵌、字符串轉(zhuǎn) NSString
    /// 字符串轉(zhuǎn) 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: 返回對應(yīng)字符串的高度
    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: 返回對應(yīng)字符串的寬度
    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 根據(jù)高度&字體 —> Size
    /// 字符串通過 label 根據(jù)高度&字體 ——> 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 根據(jù)高度&字體 —> Width
    /// 字符串通過 label 根據(jù)高度&字體 ——> 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 根據(jù)寬度&字體 —> height
    /// 字符串通過 label 根據(jù)寬度&字體 ——> 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嗅虏、字符串根據(jù)寬度 & 字體 & 行間距 —> Size
    /// 字符串根據(jù)寬度 & 字體 & 行間距 ——> Size
    /// - Parameters:
    ///   - width: 字符串最大的寬度
    ///   - heiht: 字符串最大的高度
    ///   - font: 字體的大小
    ///   - lineSpacing: 行間距
    /// - Returns: 返回對應(yīng)的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洛姑、字符串根據(jù)寬度 & 字體 & 行間距 —> width
    /// 字符串根據(jù)寬度 & 字體 & 行間距 ——> width
    /// - Parameters:
    ///   - width: 字符串最大的寬度
    ///   - heiht: 字符串最大的高度
    ///   - font: 字體的大小
    ///   - lineSpacing: 行間距
    /// - Returns: 返回對應(yīng)的 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、字符串根據(jù)寬度 & 字體 & 行間距 —> height
    /// 字符串根據(jù)寬度 & 字體 & 行間距 ——> height
    /// - Parameters:
    ///   - width: 字符串最大的寬度
    ///   - heiht: 字符串最大的高度
    ///   - font: 字體的大小
    ///   - lineSpacing: 行間距
    /// - Returns: 返回對應(yīng)的 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
    }
}

六旋恼、字符串有關(guān)數(shù)字方面的擴展

// MARK:- 五吏口、字符串有關(guān)數(shù)字方面的擴展
public enum StringCutType {
    case normal, auto
}

public extension String {

    // MARK: 5.1、將金額字符串轉(zhuǎn)化為帶逗號的金額 按照千分位劃分冰更,如  "1234567" => 1,234,567   1234567.56 => 1,234,567.56
    /// 將金額字符串轉(zhuǎn)化為帶逗號的金額 按照千分位劃分产徊,如  "1234567" => 1,234,567   1234567.56 => 1,234,567.56
    /// - Returns: 千分位的字符串
    func toThousands() -> String? {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.roundingMode = .floor
        formatter.maximumFractionDigits = 0
        formatter.minimumFractionDigits = 0
        if self.contains(".") {
            formatter.maximumFractionDigits = 2
            formatter.minimumFractionDigits = 2
            formatter.minimumIntegerDigits = 1
        }
        var num = NSDecimalNumber(string: self)
       if num.doubleValue.isNaN {
            num = NSDecimalNumber(string: "0")
        }
        let result = formatter.string(from: num)
        return result
    }

    // MARK: 5.2、字符串差不多精確轉(zhuǎn)換成Double——之所以差不多蜀细,是因為有精度損失
    /// - Important: 字符串差不多精確轉(zhuǎn)換成Double——之所以差不多舟铜,是因為有精度損失
    func accuraterDouble() -> Double? {
        guard let decimal = Decimal(string: self) else { return nil }
        JKPrint(NSDecimalNumber(decimal: decimal).doubleValue)
        return NSDecimalNumber(decimal: decimal).doubleValue
    }

    // MARK:- 5.3、去掉小數(shù)點后多余的0
    /// 去掉小數(shù)點后多余的0
    /// - Returns: 返回小數(shù)點后沒有 0 的金額
    func cutLastZeroAfterDot() -> String {
        var rst = self
        var i = 1
        if self.contains(".") {
            while i < self.count {
                if rst.hasSuffix("0") {
                    rst.removeLast()
                    i = i + 1
                } else {
                    break
                }
            }
            if rst.hasSuffix(".") {
                rst.removeLast()
            }
            return rst
        } else {
            return self
        }
    }

    // MARK: 5.4奠衔、將數(shù)字的字符串處理成  幾位 位小數(shù)的情況
    /// 將數(shù)字的字符串處理成  幾位 位小數(shù)的情況
    /// - Parameters:
    ///   - numberDecimal: 保留幾位小數(shù)
    ///   - mode: 模式
    /// - Returns: 返回保留后的小數(shù)谆刨,如果是非字符,則根據(jù)numberDecimal 返回0 或 0.00等等
    func saveNumberDecimal(numberDecimal: Int = 0, mode: NumberFormatter.RoundingMode = .floor) -> String {
        var n = NSDecimalNumber(string: self)
        if n.doubleValue.isNaN {
            n = NSDecimalNumber.zero
        }
        let formatter = NumberFormatter()
        formatter.roundingMode = mode
        // 小數(shù)位最多位數(shù)
        formatter.maximumFractionDigits = numberDecimal
       // 小數(shù)位最少位數(shù)
        formatter.minimumFractionDigits = numberDecimal
        // 整數(shù)位最少位數(shù)
        formatter.minimumIntegerDigits = 1
        // 整數(shù)位最多位數(shù)
        formatter.maximumIntegerDigits = 100
        // 獲取結(jié)果
        guard let result = formatter.string(from: n) else {
            // 異常處理
            if numberDecimal == 0 {
                return "0"
            } else {
                var zero = ""
                for _ in 0..<numberDecimal {
                    zero += zero
                }
                return "0." + zero
            }
        }
        return result
    }
}

七归斤、蘋果針對浮點類型計算精度問題提供出來的計算類

// MARK:- 六痊夭、蘋果針對浮點類型計算精度問題提供出來的計算類
/// NSDecimalNumberHandler 蘋果針對浮點類型計算精度問題提供出來的計算類
/**
 初始化方法
 roundingMode 舍入方式
 scale 小數(shù)點后舍入值的位數(shù)
 raiseOnExactness 精度錯誤處理
 raiseOnOverflow 溢出錯誤處理
 raiseOnUnderflow 下溢錯誤處理
 raiseOnDivideByZero 除以0的錯誤處理
 */
/**
 public enum RoundingMode : UInt {
 case plain = 0 是四舍五入
 case down = 1 是向下取整
 case up = 2 是向上取整
 case bankers = 3 是在四舍五入的基礎(chǔ)上,加上末尾數(shù)為5時脏里,變成偶數(shù)的規(guī)則
 }
 */
extension String {
    // MARK: 6.1她我、+
    /// +
    /// - Parameter strNumber: strNumber description
    /// - Returns: description
    public func adding(_ strNumber: String?) -> String {
        var ln = NSDecimalNumber(string: self)
        var rn = NSDecimalNumber(string: strNumber)
        if ln.doubleValue.isNaN {
            ln = NSDecimalNumber.zero
        }
        if rn.doubleValue.isNaN {
            rn = NSDecimalNumber.zero
        }
        let final = ln.adding(rn)
        return final.stringValue
    }

    // MARK: 6.2、-
    /// -
    /// - Parameter strNumber: strNumber description
    /// - Returns: description
    public func subtracting(_ strNumber: String?) -> String {
        var ln = NSDecimalNumber(string: self)
        var rn = NSDecimalNumber(string: strNumber)
        if ln.doubleValue.isNaN {
            ln = NSDecimalNumber.zero
        }
        if rn.doubleValue.isNaN {
            rn = NSDecimalNumber.zero
        }
        let final = ln.subtracting(rn)
        return final.stringValue
    }

    // MARK: 6.3迫横、*
    /// ??
    /// - Parameter strNumber: strNumber description
    /// - Returns: description
    public func multiplying(_ strNumber: String?) -> String {
        var ln = NSDecimalNumber(string: self)
        var rn = NSDecimalNumber(string: strNumber)
        if ln.doubleValue.isNaN {
            ln = NSDecimalNumber.zero
        }
        if rn.doubleValue.isNaN {
            rn = NSDecimalNumber.zero
        }
        let final = ln.multiplying(by: rn)
        return final.stringValue
    }

    // MARK: 6.4番舆、/
    /// ?
    /// - Parameter strNumber: strNumber description
   /// - Returns: description
    public func dividing(_ strNumber: String?) -> String {
        var ln = NSDecimalNumber(string: self)
        var rn = NSDecimalNumber(string: strNumber)
        if ln.doubleValue.isNaN {
            ln = NSDecimalNumber.zero
        }
        if rn.doubleValue.isNaN {
            rn = NSDecimalNumber.one
        }
        if rn.doubleValue == 0 {
            rn = NSDecimalNumber.one
        }
        let final = ln.dividing(by: rn)
        return final.stringValue
    }
}

八、字符串包含表情的處理

// MARK:- 七矾踱、字符串包含表情的處理
extension String {

    // MARK: 7.1.1郑原、檢查字符串是否包含 Emoji 表情
    /// 檢查字符串是否包含 Emoji 表情
    /// - Returns: bool
    public func containsEmoji() -> Bool {
        for scalar in unicodeScalars {
            switch scalar.value {
            case 0x1F600...0x1F64F,
                 0x1F300...0x1F5FF,
                 0x1F680...0x1F6FF,
                 0x2600...0x26FF,
                 0x2700...0x27BF,
                 0xFE00...0xFE0F:
                return true
            default:
                continue
            }
        }
        return false
    }

    // MARK: 7.1.2济炎、檢查字符串是否包含 Emoji 表情
    /// 檢查字符串是否包含 Emoji 表情
    /// - Returns: bool
    public func includesEmoji() -> Bool {
        for i in 0...length {
            let c: unichar = (self as NSString).character(at: i)
            if (0xD800 <= c && c <= 0xDBFF) || (0xDC00 <= c && c <= 0xDFFF) {
                return true
            }
        }
        return false
    }

    // MARK: 7.2若未、去除字符串中的Emoji表情
    /// 去除字符串中的Emoji表情
    /// - Parameter text: 字符串
    /// - Returns: 去除Emoji表情后的字符串
    public func deleteEmoji() -> String {
        do {
            let regex = try NSRegularExpression(pattern: "[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]", options: NSRegularExpression.Options.caseInsensitive)
        
            let modifiedString = regex.stringByReplacingMatches(in: self, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.length), withTemplate: "")
        
            return modifiedString
        } catch {
            JKPrint(error)
        }
        return ""
    }
}

九恩商、字符串的一些正則校驗

// MARK:- 八、字符串的一些正則校驗
extension String {

    // MARK: 8.1圣蝎、判斷是否全是空白,包括空白字符和換行符號刃宵,長度為0返回true
    /// 判斷是否全是空白,包括空白字符和換行符號,長度為0返回true
    public var isBlank: Bool {
        return trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines) == ""
    }

    // MARK: 8.2徘公、判斷是否全十進制數(shù)字,長度為0返回false
    /// 判斷是否全十進制數(shù)字哮针,長度為0返回false
    public var isDecimalDigits: Bool {
        if isEmpty {
            return false
        }
        // 去除什么的操作
        return trimmingCharacters(in: NSCharacterSet.decimalDigits) == ""
    }

    // MARK: 8.3关面、判斷是否是整數(shù)
    /// 判斷是否是整數(shù)
    public var isPureInt: Bool {
        let scan: Scanner = Scanner(string: self)
        var n: Int = 0
        return scan.scanInt(&n) && scan.isAtEnd
    }

    // MARK: 8.4坦袍、判斷是否是Float,此處Float是包含Int的,即Int是特殊的Float
    /// 判斷是否是Float等太,此處Float是包含Int的捂齐,即Int是特殊的Float
    public var isPureFloat: Bool {
        let scan: Scanner = Scanner(string: self)
        var n: Float = 0.0
        return scan.scanFloat(&n) && scan.isAtEnd
    }

    // MARK: 8.5、判斷是否全是字母缩抡,長度為0返回false
    /// 判斷是否全是字母奠宜,長度為0返回false
    public var isLetters: Bool {
        if isEmpty {
            return false
        }
        return trimmingCharacters(in: NSCharacterSet.letters) == ""
    }

    // MARK: 8.6、判斷是否是中文, 這里的中文不包括數(shù)字及標(biāo)點符號
    /// 判斷是否是中文, 這里的中文不包括數(shù)字及標(biāo)點符號
    public var isChinese: Bool {
        let mobileRgex = "(^[\u{4e00}-\u{9fef}]+$)"
        let checker: NSPredicate = NSPredicate(format: "SELF MATCHES %@", mobileRgex)
        return checker.evaluate(with: self)
    }

    // MARK: 8.7瞻想、是否是有效昵稱压真,即允許“中文”、“英文”蘑险、“數(shù)字”
    /// 是否是有效昵稱滴肿,即允許“中文”、“英文”佃迄、“數(shù)字”
    public var isValidNickName: Bool {
        let rgex = "(^[\u{4e00}-\u{9faf}_a-zA-Z0-9]+$)"
        let checker: NSPredicate = NSPredicate(format: "SELF MATCHES %@", rgex)
        return checker.evaluate(with: self)   
    }

    // MARK: 8.8泼差、判斷是否是有效的手機號碼
    /// 判斷是否是有效的手機號碼
    public var isValidMobile: Bool {
        let mobileRgex = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199)\\d{8}$"
        let checker: NSPredicate = NSPredicate(format: "SELF MATCHES %@", mobileRgex)
        return checker.evaluate(with: self)
    }

    // MARK: 8.9、判斷是否是有效的電子郵件地址
    /// 判斷是否是有效的電子郵件地址
    public var isValidEmail: Bool {
        let mobileRgex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
        let checker: NSPredicate = NSPredicate(format: "SELF MATCHES %@", mobileRgex)
        return checker.evaluate(with: self)
    }

    // MARK: 8.10呵俏、判斷是否有效的身份證號碼堆缘,不是太嚴(yán)格
    /// 判斷是否有效的身份證號碼,不是太嚴(yán)格
    public var isValidIDCardNumber: Bool {
        let mobileRgex = "^(\\d{15})|((\\d{17})(\\d|[X]))$"
        let checker: NSPredicate = NSPredicate(format: "SELF MATCHES %@", mobileRgex)
        return checker.evaluate(with: self)
    }

    // MARK: 8.11普碎、嚴(yán)格判斷是否有效的身份證號碼,檢驗了省份吼肥,生日,校驗位随常,不過沒檢查市縣的編碼
    /// 嚴(yán)格判斷是否有效的身份證號碼,檢驗了省份潜沦,生日,校驗位绪氛,不過沒檢查市縣的編碼
    public var isValidIDCardNumStrict: Bool {
        let str = trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)
        let len = str.count
        if !str.isValidIDCardNumber {
            return false
        }
        // 省份代碼
        let areaArray = ["11", "12", "13", "14", "15", "21", "22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63", "64", "65", "71", "81", "82", "91"]
        if !areaArray.contains(str.sub(to: 2)) {
            return false
        }
        var regex = NSRegularExpression()
        var numberOfMatch = 0
        var year = 0
        switch len {
        case 15:
            // 15位身份證
            // 這里年份只有兩位唆鸡,00被處理為閏年了,對2000年是正確的枣察,對1900年是錯誤的争占,不過身份證是1900年的應(yīng)該很少了
            year = Int(str.sub(start: 6, length: 2))!
            if isLeapYear(year: year) { // 閏年
                do {
                    // 檢測出生日期的合法性
                    regex = try NSRegularExpression(pattern: "^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$", options: .caseInsensitive)
                } catch {}
            } else {
                do {
                    // 檢測出生日期的合法性
                    regex = try NSRegularExpression(pattern: "^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$", options: .caseInsensitive)
                } catch {}
            }
            numberOfMatch = regex.numberOfMatches(in: str, options: NSRegularExpression.MatchingOptions.reportProgress, range: NSMakeRange(0, len))

            if numberOfMatch > 0 {
                return true
            } else {
                return false
            }
        case 18:
            // 18位身份證
            year = Int(str.sub(start: 6, length: 4))!
            if isLeapYear(year: year) {
                // 閏年
                do {
                    // 檢測出生日期的合法性
                    regex = try NSRegularExpression(pattern: "^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$", options: .caseInsensitive)
                } catch {}
            } else {
                do {
                    // 檢測出生日期的合法性
                    regex = try NSRegularExpression(pattern: "^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$", options: .caseInsensitive)
                } catch {}
            }
            numberOfMatch = regex.numberOfMatches(in: str, options: NSRegularExpression.MatchingOptions.reportProgress, range: NSMakeRange(0, len))
            if numberOfMatch > 0 {
                var s = 0
                let jiaoYan = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3]
                for i in 0 ..< 17 {
                    if let d = Int(str.slice(i ..< (i + 1))) {
                        s += d * jiaoYan[i % 10]
                    } else {
                        return false
                    }
                }
                let Y = s % 11
                let JYM = "10X98765432"
                let M = JYM.sub(start: Y, length: 1)
                if M == str.sub(start: 17, length: 1) {
                   return true
                } else {
                    return false
                }
            } else {
                return false
            }
        default:
            return false
        }
    }
        
    // MARK: 8.12、校驗字符串位置是否合理序目,并返回String.Index
    /// 校驗字符串位置是否合理臂痕,并返回String.Index
    /// - Parameter original: 位置
    /// - Returns: String.Index
    public func validIndex(original: Int) -> String.Index {
        switch original {
        case ...startIndex.utf16Offset(in: self):
             return startIndex
        case endIndex.utf16Offset(in: self)...:
             return endIndex
        default:
             return index(startIndex, offsetBy: original)
        }
    }

    // MARK: 8.13、隱藏手機號中間的幾位
    /// 隱藏手機號中間的幾位
    /// - Parameter combine: 隱藏的字符串(替換的類型)
    /// - Returns: 返回隱藏的手機號
    public func hidePhone(combine: String = "****") -> String {
         if self.count >= 11 {
            let pre = self.sub(start: 0, length: 3)
            let post = self.sub(start: 7, length: 4)
            return pre + combine + post
        } else {
            return self
        }
    }

    // MARK:- private 方法
    // MARK: 是否是閏年
    /// 是否是閏年
    /// - Parameter year: 年份
    /// - Returns: 返回是否是閏年
    private func isLeapYear(year: Int) -> Bool {
        if year % 400 == 0 {
            return true
        } else if year % 100 == 0 {
            return false
        } else if year % 4 == 0 {
            return true
        } else {
            return false
        }
    }
}

十猿涨、字符串截取的操作

// MARK:- 九握童、字符串截取的操作
extension String {

    // MARK: 9.1、截取字符串從開始到 index
    /// 截取字符串從開始到 index
    /// - Parameter index: 截取到的位置
    /// - Returns: 截取后的字符串
    public func sub(to index: Int) -> String {
        let end_Index = validIndex(original: index)
        return String(self[startIndex ..< end_Index])
    }

    // MARK: 9.2叛赚、截取字符串從index到結(jié)束
    /// 截取字符串從index到結(jié)束
   /// - Parameter index: 截取結(jié)束的位置
    /// - Returns: 截取后的字符串
    public func sub(from index: Int) -> String {
        let start_index = validIndex(original: index)
        return String(self[start_index ..< endIndex])
    }

    // MARK: 9.3澡绩、獲取指定位置和長度的字符串
    /// 獲取指定位置和大小的字符串
    /// - Parameters:
    ///   - start: 開始位置
    ///   - length: 長度
    /// - Returns: 截取后的字符串
    public func sub(start: Int, length: Int = -1) -> String {
        var len = length
        if len == -1 {
            len = count - start
        }
        let st = index(startIndex, offsetBy: start)
        let en = index(st, offsetBy: len)
        let range = st ..< en
        return String(self[range]) // .substring(with:range)
    }

    // MARK: 9.4稽揭、切割字符串(區(qū)間范圍 前閉后開)
    /**
     https://blog.csdn.net/wang631106979/article/details/54098910
     CountableClosedRange:可數(shù)的閉區(qū)間,如 0...2
     CountableRange:可數(shù)的開區(qū)間肥卡,如 0..<2
     ClosedRange:不可數(shù)的閉區(qū)間溪掀,如 0.1...2.1
     Range:不可數(shù)的開居間,如 0.1..<2.1
     */
    /// 切割字符串(區(qū)間范圍 前閉后開)
    /// - Parameter range: 范圍
    /// - Returns: 切割后的字符串
    public func slice(_ range: CountableRange<Int>) -> String { // 如 sliceString(2..<6)
        /**
         upperBound(上界)
         lowerBound(下界)
         */
        let startIndex = validIndex(original: range.lowerBound)
        let endIndex = validIndex(original: range.upperBound)
        guard startIndex < endIndex else {
            return ""
        }
        return String(self[startIndex ..< endIndex])
    }

    // MARK: 9.5步鉴、用整數(shù)返回子字符串開始的位置
    /// 用整數(shù)返回子字符串開始的位置
    /// - Parameter sub: 字符串
    /// - Returns: 返回字符串的位置
    public func position(of sub: String) -> Int {
        if sub.isEmpty {
            return 0
        }
        var pos = -1
        if let range = self.range(of: sub) {
            if !range.isEmpty {
                pos = distance(from: startIndex, to: range.lowerBound)
            }
        }
        return pos
    }
}

十揪胃、字符串編碼的處理

// MARK:- 十、字符串編碼的處理
extension String {

    // MARK: 10.1氛琢、特殊字符編碼處理urlEncoded
    /// url編碼 默認(rèn)urlQueryAllowed
    public func urlEncoding(characters: CharacterSet = .urlQueryAllowed) -> String {
        let encodeUrlString = self.addingPercentEncoding(withAllowedCharacters:
        characters)
        return encodeUrlString ?? ""
    }

    // MARK:- 10.2喊递、url編碼 Alamofire AFNetworking 處理方式 推薦使用
    /// url編碼 Alamofire AFNetworking 處理方式 推薦使用
    public var urlEncoded: String {
        // does not include "?" or "/" due to RFC 3986 - Section 3.4
        let generalDelimitersToEncode = ":#[]@"
        let subDelimitersToEncode = "!$&'()*+,;="
    
        var allowedCharacterSet = CharacterSet.urlQueryAllowed
    allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
        let encodeUrlString = self.addingPercentEncoding(withAllowedCharacters:
        allowedCharacterSet)
        return encodeUrlString ?? ""
    }

    // MARK: 10.3、url編碼 會對所有特殊字符做編碼  特殊情況下使用
    /// url編碼 會對所有特殊字符做編碼  特殊情況下使用
    public var urlAllEncoded: String {
        let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
        let subDelimitersToEncode = "!$&'()*+,;=/?_-.~"
    
        var allowedCharacterSet = CharacterSet.urlQueryAllowed
    allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
        let encodeUrlString = self.addingPercentEncoding(withAllowedCharacters:
        allowedCharacterSet)
        return encodeUrlString ?? ""
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末艺沼,一起剝皮案震驚了整個濱河市册舞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌障般,老刑警劉巖调鲸,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挽荡,居然都是意外死亡藐石,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門定拟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來于微,“玉大人,你說我怎么就攤上這事青自≈暌溃” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵延窜,是天一觀的道長恋腕。 經(jīng)常有香客問我,道長逆瑞,這世上最難降的妖魔是什么荠藤? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮获高,結(jié)果婚禮上哈肖,老公的妹妹穿的比我還像新娘。我一直安慰自己念秧,他們只是感情好淤井,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般庄吼。 火紅的嫁衣襯著肌膚如雪缎除。 梳的紋絲不亂的頭發(fā)上严就,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天总寻,我揣著相機與錄音,去河邊找鬼梢为。 笑死渐行,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铸董。 我是一名探鬼主播祟印,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粟害!你這毒婦竟也來了蕴忆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤悲幅,失蹤者是張志新(化名)和其女友劉穎套鹅,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汰具,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡卓鹿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了留荔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吟孙。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖聚蝶,靈堂內(nèi)的尸體忽然破棺而出杰妓,到底是詐尸還是另有隱情,我是刑警寧澤碘勉,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布巷挥,位于F島的核電站,受9級特大地震影響恰聘,放射性物質(zhì)發(fā)生泄漏句各。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一晴叨、第九天 我趴在偏房一處隱蔽的房頂上張望凿宾。 院中可真熱鬧,春花似錦兼蕊、人聲如沸初厚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽产禾。三九已至排作,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亚情,已是汗流浹背妄痪。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留楞件,地道東北人衫生。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像土浸,于是被迫代替她去往敵國和親罪针。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355