import UIKit

public extension Optional {
    
    // Check NotEmpty
    var isNotEmpty: Bool {
        guard let str = self as? String else {
            return false
        }
        return !str.isEmpty
    }
    
    // Check NotEmpty return String
    var isNotEmptyString: String {
        guard let str = self as? String else {
            return ""
        }
        return str
    }
}

extension NSMutableAttributedString {
    
    /// 문자열 특정범위 폰트/컬러 속성변경
    func setAttribute(font: UIFont, color: UIColor, start: Int, length: Int) {
        self.addAttributes([NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: color],
                           range: NSMakeRange(start, length))
    }
}

extension String {
    
    /// 유저가 선택한 언어셋으로 변경
     var localized: String {
        
        let lang = UserData.deviceLocale.settingLanguageCode
        
        /* en, ko, ja, zh 4개국 지원 기본 en
         - struct LocaleSetting : 언어셋 설정 참조
         - 중국어의 경우 간체로 강제 세팅
         - 앱 언어셋 zh-Hans (간체) 사용 (번체, 홍콩) 코드 간체로 통일
         */
         
         
        guard let path = Bundle.main.path(forResource: lang == "zh" ? "zh-Hans" : lang, ofType: "lproj") else {
            return ""
        }
        let bundle = Bundle(path: path)

        return NSLocalizedString(self, tableName: "", bundle: bundle!, value: "", comment: "")
        
    }
    
    public var bytes: Array<UInt8> {
    	data(using: String.Encoding.utf8, allowLossyConversion: true)?.bytes ?? Array(utf8)
  	}
  
    ///Base64 인코딩 String
     func base64EncodedString() -> String? {
        return Data(self.utf8).base64EncodedString()
    }
    
    ///Base64 디코딩 String
     func base64DecodedString() -> String? {
        guard let data = Data(base64Encoded: self) else {
            return nil
        }
    
        return String(data: data, encoding: .utf8)
    }
    
    /// Base64 Encoding
    func toBase64() -> String? {
        guard let data = self.data(using: String.Encoding.utf8) else {
            return nil
        }
        return data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
        
    }
    
    /// Base64 Decoding
    func fromBase64() -> String? {
        guard let data = Data(base64Encoded: self, options: Data.Base64DecodingOptions(rawValue: 0)) else {
            return nil
        }
        return String(data: data as Data, encoding: String.Encoding.utf8)
    }
    
    /// JSON String to Dictionary Convert
    func convertToDictionary() -> [String: Any]? {
        if let data = data(using: .utf8) {
            return try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
        }
        return nil
    }
    
    /// String split return array
    public func arrayBySplit(splitter: String? = nil) -> [String] {
        if let s = splitter {
            return self.components(separatedBy: s)
        } else {
            return self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines)
        }
    }
    
    var ns : NSString? {
        get {
            return NSString(string: self)
        }
    }
    
    static func randomString(length: Int) -> String {
        let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        let len = UInt32(letters.length)
        var randomString = ""
        for _ in 0 ..< length {
            let rand = arc4random_uniform(len)
            var nextChar = letters.character(at: Int(rand))
            randomString += NSString(characters: &nextChar, length: 1) as String
        }
        return randomString
    }
    
    /// 문자열 공백 제거
     var stringTrim: String{
       return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
    }
    
    /// 문자열  chracter count
    public var length: Int {
        return self.count
    }
    
    /// 문자열 길이  ( {0, 5} )
    var fullRange: NSRange {
      return NSRange(location: 0, length: self.count)
    }
    
    var escapedStringLiteralRemove: String {
      return self
        .replacingOccurrences(of: "\\", with: "")
        .replacingOccurrences(of: "\"", with: "")
        .replacingOccurrences(of: "\t", with: "")
        .replacingOccurrences(of: "\r", with: "")
        .replacingOccurrences(of: "\n", with: "")
    }
    
    var escapedStringLiteral: String {
      return self
        .replacingOccurrences(of: "\\", with: "\\\\")
        .replacingOccurrences(of: "\"", with: "\\\"")
        .replacingOccurrences(of: "\t", with: "\\t")
        .replacingOccurrences(of: "\r", with: "\\r")
        .replacingOccurrences(of: "\n", with: "\\n")
    }

    var commentString: String {
      return self
        .replacingOccurrences(of: "\r\n", with: " ")
        .replacingOccurrences(of: "\r", with: " ")
        .replacingOccurrences(of: "\n", with: " ")
    }
    
    /// 문자열의 첫글자 소문자로 변경
    var lowercaseFirstCharacter: String {
      if self.count <= 1 { return self.lowercased() }
      let index = self.index(startIndex, offsetBy: 1)
      return self[..<index].lowercased() + self[index...]
    }
    
    /// 문자열의 첫글자 대문자로 변경
    var uppercaseFirstCharacter: String {
      if self.count <= 1 { return self.uppercased() }
      let index = self.index(startIndex, offsetBy: 1)
      return self[..<index].uppercased() + self[index...]
    }

    /// 들여쓰기 함수
     func indent(with indentation: String) -> String {
      return self
        .components(separatedBy: "\n")
        .map { line in line .isEmpty ? "" : "\(indentation)\(line)" }
        .joined(separator: "\n")
    }
    
    /// String localized with comment
    func localizedWithComment(comment: String) -> String {
        return NSLocalizedString(self, comment:comment)
    }
    
    /// true / false string -> Bool
    var boolValue: Bool {
        (self as NSString).boolValue
      }
    
    /// String -> Date 변환
    /**
      - let date = "20230711".toDate(format: "yyyyMMdd")
     */
    func toDate(format: String) -> Date? { //"yyyy-MM-dd HH:mm:ss"
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = format//"yyyy-MM-dd HH:mm:ss"
        dateFormatter.timeZone = TimeZone(identifier: "UTC")
        if let date = dateFormatter.date(from: self) {
            return date
        } else {
            return nil
        }
    }
    
    func validateNumber() -> Bool {
        let regex = "[0-9]"
        return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: self)
    }
    
    /// Phone Number validation
    func validatePhoneNumber(candidate: String) -> Bool {
        let regex = "^01([0|1|6|7|8|9]?)-?([0-9]{3,4})-?([0-9]{4})$"
        return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: candidate)
    }
    
    /// E-mail address validation
     func validateEmail() -> Bool {
        let emailRegEx = "^.+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*$"
        
        let predicate = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return predicate.evaluate(with: self)
    }
    
    /// Password validation
     func validatePassword() -> Bool {
        let passwordRegEx = "^(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z]).{8,16}$"
        
        let predicate = NSPredicate(format:"SELF MATCHES %@", passwordRegEx)
        return predicate.evaluate(with: self)
    }
    
    /// 정규식 데이터 추출
    /// 참고사이트 : https://eunjin3786.tistory.com/12
    func getArrayAfterRegex(regex: String) -> [String] {
        
        do {
            let regex = try NSRegularExpression(pattern: regex)
            let results = regex.matches(in: self,
                                        range: NSRange(self.startIndex..., in: self))
            return results.map {
                String(self[Range($0.range, in: self)!])
            }
        } catch let error {
            print("invalid regex: \(error.localizedDescription)")
            return []
        }
    }
    
    /// 정규식 데이터 체크
    /// 참고사이트 : https://nsios.tistory.com/139
    /**
     한글/영문만 입력가능 : "^[가-힣ㄱ-ㅎㅏ-ㅣa-zA-Z]{0,}$"
     숫자만 입력가능 : "^[0-9]{0,8}$" => (0,8) 8자까지 입력가능
                "^[0-9]{0,}$" => {0,} 0자 이상
     */
    func getStringRegex(pattern: String) -> Bool {
        if let regex = try? NSRegularExpression(pattern: pattern) {
            return regex.firstMatch(in: self, options: [], range: NSRange(location: 0, length: self.count)) != nil
        }
        
        return false
    }
    
    /**
     - 문자열 자르기 (자리수에 맞게 자르기)
       EX)  면허번호 14-00-016448-70
     let licenseNumber = 140001644870
     let text1 = licenseNumber.substring(from: 0, to: 1)
     let text2 = licenseNumber.substring(from: 2, to: 3)
     let text3 = licenseNumber.substring(from: 4, to: 9)
     let text4 = licenseNumber.substring(from: 10, to: 11)
     */
    func substring(from: Int, to: Int) -> String {
        guard from < count, to >= 0, to - from >= 0 else {
            return ""
        }
        
        // Index 값 획득
        let startIndex = index(self.startIndex, offsetBy: from)
        let endIndex = index(self.startIndex, offsetBy: to + 1) // '+1'이 있는 이유: endIndex는 문자열의 마지막 그 다음을 가리키기 때문
        
        // 파싱
        return String(self[startIndex ..< endIndex])
    }
    
// MARK: sha256
    func sha256() -> String {
        if let stringData = self.data(using: String.Encoding.utf8) {
            return hexStringFromData(input: digest(input: stringData as NSData))
        }
        return ""
    }
    
	//Bridging-Header.h #import <CommonCrypto/CommonDigest.h>
    private func digest(input : NSData) -> NSData {
        let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
        var hash = [UInt8](repeating: 0, count: digestLength)
        CC_SHA256(input.bytes, UInt32(input.length), &hash)
        return NSData(bytes: hash, length: digestLength)
    }
    
    private func hexStringFromData(input: NSData) -> String {
        var bytes = [UInt8](repeating: 0, count: input.length)
        input.getBytes(&bytes, length: input.length)
        
        var hexString = ""
        for byte in bytes {
            hexString += String(format:"%02x", UInt8(byte))
        }
        
        return hexString
    }
    
    // MARK: - [fillLeftDigits 왼쪽 기준 데이터 채우기 수행 실시]
    /*
     ex) 2진데이터 자리 채우기
     "10".fillLeftDigits(length: 8, char:"0")
     결과 : "10" => "00000010"
     */
    func fillLeftDigits(length:Int, char:String) -> String {
        
        var returnData = ""
        if self.count < length
            && char.count != 0 && char.count == 1 {
            let countValue = length - self.count
            
            for _ in stride(from: 0, through: countValue-1, by: 1) {
                returnData = returnData + char
            }
            returnData = returnData + self
        }
        else {
            returnData = self
        }
        
        return returnData
    }
}

+ Recent posts