Last active
May 16, 2024 07:18
-
-
Save kk-vv/87b16a88a9ffd813f998287f4b94533f to your computer and use it in GitHub Desktop.
Shitcoin price format eg. 0.0{6}4518
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum RegularType { | |
case scientificNotation | |
case shitcoinPrice | |
case url | |
case evmAddress | |
case btcAddress | |
case solanaAddress | |
case zeroAmount | |
case string(String) | |
case validAmountInput(_ decimals: Int) | |
case validSlippage | |
case imageURL | |
var expression: String { | |
switch self { | |
case .scientificNotation: | |
return #"[-+]?\d*(?:\.(\d*))?e([+-]\d+)"# | |
case .shitcoinPrice: | |
return #"[-+]?0.0\{(?<zero>\d*)\}(?<decimal>\d+)"# | |
case .url: | |
return #"((https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])"# | |
case .evmAddress: | |
return #"^(ethereum)?(:)?0x[a-fA-F0-9]{40}$"# | |
case .btcAddress: | |
return #"^((bc|tb)(0([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59})|1[ac-hj-np-z02-9]{8,87})|([13]|[mn2])[a-km-zA-HJ-NP-Z1-9]{25,39})$"# | |
case .solanaAddress: | |
return #"^([1-9A-HJ-NP-Za-km-z]{32,44})$"# | |
case .zeroAmount: | |
return #"^0+\.?0*$"# | |
case .validAmountInput(let decimals): | |
return "(\\+)?(([0]|(0[.]\\d{0,\(decimals)}))|([1-9]\\d{0,30}(([.]\\d{0,\(decimals)})?)))?" | |
case .validSlippage: | |
return #"(([0]|(0[.]\d{0,1}))|([1-4]\d{0,1}(([.]\d{0,1})?)))?"# | |
case .imageURL: | |
return #"https?://(.+/)+.+(\.(gif|png|jpg|jpeg|webp|svg|psd|bmp|tif))"# | |
case .string(let string): | |
return string | |
} | |
} | |
var predicate: NSPredicate { | |
.init(format: "SELF MATCHES %@", self.expression) | |
} | |
} | |
extension String { | |
func match(type: RegularType, trimmingEmptyCharacters: Bool = true) -> Bool { | |
let matchString = trimmingEmptyCharacters ? self.trimmingCharacters(in: .whitespacesAndNewlines) : self | |
return type.predicate.evaluate(with: matchString.lowercased()) | |
} | |
} | |
fileprivate let MaxZeroDecimalCount = 4 | |
extension String { | |
func formattedPrice(convertCurrency: Bool = true, currencySymbol: Bool = true) -> String { | |
if self.lowercased() == "n/a" { | |
return self.groupedBy3Numbers | |
} | |
let currency = UserConfigStorage.shared.config.currency | |
let ratio = CurrencyRatio.live.ratioUSDWith(currency: currency) | |
let value = self.deformatedToPureString | |
var convertValue = value | |
if convertCurrency { | |
convertValue = "\((Double(value) ?? 0) * ratio)".deformatedToPureString | |
} | |
let bigValue = convertValue.bigInt(decimals: 0) | |
let bigValueString = "\(bigValue)" | |
if currency == .cny, bigValueString.count >= 9 { | |
let dt = (bigValueString.count - 9) | |
let head = bigValueString[0..<(2 + dt)] | |
let tail = bigValueString[(2 + dt)..<(4+dt)] | |
let validValueString = "\(head).\(tail)".trimmingZeroDecimal + "亿" | |
if currencySymbol { | |
return "\(currency.symbol)\(validValueString.groupedBy3Numbers)" | |
} else { | |
return validValueString.groupedBy3Numbers | |
} | |
} else if bigValueString.count >= 10 { | |
let dt = (bigValueString.count - 10) | |
let head = bigValueString[0..<(1 + dt)] | |
let tail = bigValueString[(1 + dt)..<(3+dt)] | |
let validValueString = "\(head).\(tail)".trimmingZeroDecimal + "B" | |
if currencySymbol { | |
return "\(currency.symbol)\(validValueString.groupedBy3Numbers)" | |
} else { | |
return validValueString.groupedBy3Numbers | |
} | |
} | |
if currencySymbol { | |
return "\(currency.symbol)\(convertValue.toScientific.shitCoinPrice.groupedBy3Numbers)" | |
} | |
return convertValue.toScientific.shitCoinPrice.groupedBy3Numbers | |
} | |
var formattedAmount: String { | |
"\(self.toScientific.shitCoinPrice)".groupedBy3Numbers | |
} | |
var groupedBy3Numbers: String { | |
if self.contains(".") { | |
var left = self.components(separatedBy: ".").first! | |
let right = self.components(separatedBy: ".").last! | |
left = left.replacingOccurrences(of: "(?<=\\d)(?=(\\d\\d\\d)+(?!\\d))", with: ",", options: .regularExpression, range: left.startIndex..<left.endIndex) | |
return "\(left).\(right)" | |
} else { | |
return self.replacingOccurrences(of: "(?<=\\d)(?=(\\d\\d\\d)+(?!\\d))", with: ",", options: .regularExpression, range: self.startIndex..<self.endIndex) | |
} | |
} | |
var withCurrentCurrencySymbol: String { | |
let currency = UserConfigStorage.shared.config.currency | |
return "\(currency.symbol)\(self)" | |
} | |
var withUSDCurrenySymbol: String { | |
return "$\(self)" | |
} | |
func formattedLP(convertCurrency: Bool) -> String { | |
if self.lowercased() == "n/a" { | |
return self | |
} | |
let currency = UserConfigStorage.shared.config.currency | |
let ratio = CurrencyRatio.live.ratioUSDWith(currency: currency) | |
let value = self.deformatedToPureString | |
var convertValue = value | |
if convertCurrency { | |
convertValue = "\((Double(value) ?? 0) * ratio)".deformatedToPureString | |
} | |
let values = convertValue.components(separatedBy: ".") | |
let intValue = Double(values.first ?? "0") ?? 0 | |
if intValue >= 1000000000000 { | |
let string = String(format: "%.1f", intValue / 1000000000000).trimmingZeroDecimal | |
return "\(string)T" | |
} else if intValue >= 1000000000 { | |
let string = String(format: "%.1f", intValue / 1000000000).trimmingZeroDecimal | |
return "\(string)B" | |
} else if intValue >= 1000000 { | |
let string = String(format: "%.1f", intValue / 1000000).trimmingZeroDecimal | |
return "\(string)M" | |
} else if intValue >= 1000 { | |
let string = String(format: "%.1f", intValue / 1000).trimmingZeroDecimal | |
return "\(string)K" | |
} else { | |
return convertValue.formattedPrice(convertCurrency:false, currencySymbol: false) | |
} | |
} | |
var shortAmountFormat: String { | |
let convertValue = self.deformatedToPureString | |
let values = convertValue.components(separatedBy: ".") | |
let intValue = Double(values.first ?? "0") ?? 0 | |
let language = UserConfigStorage.shared.config.language | |
if language == .chinese || language == .chineseTraditional { | |
let wanString = language == .chinese ? "万" : "萬" | |
let yiString = language == .chinese ? "亿" : "億" | |
if intValue >= 100000000 { | |
let string = String(format: "%.1f", intValue / 100000000).trimmingZeroDecimal | |
return "\(string)\(yiString)" | |
} else if intValue >= 10000 { | |
let string = String(format: "%.1f", intValue / 10000).trimmingZeroDecimal | |
return "\(string)\(wanString)" | |
} else if intValue >= 1000 { | |
let string = String(format: "%.1f", intValue / 1000).trimmingZeroDecimal | |
return "\(string)千" | |
} else { | |
return convertValue.shitCoinPrice | |
} | |
} else { | |
if intValue >= 1000000000000 { | |
let string = String(format: "%.1f", intValue / 1000000000000).trimmingZeroDecimal | |
return "\(string)T" | |
} else if intValue >= 1000000000 { | |
let string = String(format: "%.1f", intValue / 1000000000).trimmingZeroDecimal | |
return "\(string)B" | |
} else if intValue >= 1000000 { | |
let string = String(format: "%.1f", intValue / 1000000).trimmingZeroDecimal | |
return "\(string)M" | |
} else if intValue >= 1000 { | |
let string = String(format: "%.1f", intValue / 1000).trimmingZeroDecimal | |
return "\(string)K" | |
} else { | |
return convertValue.shitCoinPrice | |
} | |
} | |
} | |
/// To scientific while less than 0.000001 or return self | |
var toScientific: String { | |
if self.match(type: .scientificNotation) { | |
return self | |
} else if self.contains(".") { | |
let pattern = #"^0.(?<decimal>[0]+)(?<value>[1-9]+)"# | |
let range = NSRange(self.startIndex..<self.endIndex, in: self) | |
if let regex = try? NSRegularExpression(pattern: pattern) { | |
let matches = regex.matches(in: self, range: range) | |
guard matches.first != nil else { | |
return self | |
} | |
var captures: [String: String] = [:] | |
for match in matches { | |
for name in ["decimal", "value"] { | |
let matchRange = match.range(withName: name) | |
// Extract the substring matching the named capture group | |
if let substringRange = Range(matchRange, in: self) { | |
let capture = String(self[substringRange]) | |
captures[name] = capture | |
} | |
} | |
} | |
if let decimal = captures["decimal"]?.count, decimal >= MaxZeroDecimalCount, | |
let valueStr = captures["value"], !valueStr.isEmpty { | |
return "\(valueStr)e-\(decimal + valueStr.count)" | |
} | |
} | |
} | |
return self | |
} | |
/// Format to 0.0{x}xxx while less than 0.000001 | |
var shitCoinPrice: String { | |
if self.match(type: .scientificNotation) { | |
let pattern = #"^(?<symbol>[-+]?)(?<number>\d*)(?<decimal>\.([0-9]*))?e(?<notation>[+-]\d+)"# | |
let range = NSRange(self.startIndex..<self.endIndex, in: self) | |
if let regex = try? NSRegularExpression(pattern: pattern) { | |
let matches = regex.matches(in: self, range: range) | |
guard matches.first != nil else { | |
return self | |
} | |
var captures: [String: String] = [:] | |
for match in matches { | |
// For each matched range, extract the named capture group | |
for name in ["symbol", "number", "decimal", "notation"] { | |
let matchRange = match.range(withName: name) | |
// Extract the substring matching the named capture group | |
if let substringRange = Range(matchRange, in: self) { | |
let capture = String(self[substringRange]) | |
captures[name] = capture | |
} | |
} | |
} | |
let symbol = captures["symbol"] ?? "" | |
guard let number = captures["number"], | |
let notation = captures["notation"], | |
notation.hasPrefix("-"), | |
let notationNumber = Int(notation) | |
else { | |
return self | |
} | |
let decimal = captures["decimal"] ?? "" | |
var fixNotation = abs(Int(notationNumber)) - 1 | |
fixNotation = fixNotation - number.count + 1 // 0{fixNotation} | |
if fixNotation > 0 { | |
var numbers = "\(number)\(decimal.replacingOccurrences(of: ".", with: ""))" | |
if numbers.count > 4 { | |
numbers = numbers[0..<4] | |
} | |
if fixNotation >= MaxZeroDecimalCount { | |
return "\(symbol)0.0{\(fixNotation)}\(numbers)" | |
} else { | |
let zeros = String(repeating: "0", count: fixNotation) | |
return "\(symbol)0.\(zeros)\(numbers)" | |
} | |
} else { | |
return self.limitedShitCoinPrice | |
} | |
} else { | |
return self.limitedShitCoinPrice | |
} | |
} else { | |
return self.limitedShitCoinPrice | |
} | |
} | |
private var limitedShitCoinPrice: String { | |
if self.contains(".") { | |
let pattern = #"^(?<symbol>[-+]?)(?<number>\d+)\.(?<decimal>[0]*\d{0,4})"# | |
let range = NSRange(self.startIndex..<self.endIndex, in: self) | |
if let regex = try? NSRegularExpression(pattern: pattern) { | |
let matches = regex.matches(in: self, range: range) | |
guard matches.first != nil else { | |
return self | |
} | |
var captures: [String: String] = [:] | |
for match in matches { | |
for name in ["symbol", "number", "decimal"] { | |
let matchRange = match.range(withName: name) | |
// Extract the substring matching the named capture group | |
if let substringRange = Range(matchRange, in: self) { | |
let capture = String(self[substringRange]) | |
captures[name] = capture | |
} | |
} | |
} | |
let symbol = captures["symbol"] ?? "" | |
guard let number = captures["number"] else { | |
return self | |
} | |
if let decimal = captures["decimal"], !decimal.isEmpty { | |
var finalStr = number | |
let numberValue = Int(number) ?? 0 | |
if numberValue > 0 { | |
let maxLen = min(2, decimal.count) | |
let decimalStr = decimal[0..<maxLen] | |
finalStr += ".\(decimalStr)" | |
} else { | |
finalStr += ".\(decimal)" | |
} | |
return "\(symbol)\(finalStr.trimmingZeroDecimal)" | |
} | |
return "\(symbol)\(number)" | |
} | |
} | |
return self | |
} | |
var trimmingZeroDecimal: String { | |
var finalStr = self.trimmingCharacters(in: .whitespacesAndNewlines) | |
if finalStr.firstIndex(of: ".") != nil { | |
if let regex = try? NSRegularExpression(pattern: "[0]+$") { | |
finalStr = regex.stringByReplacingMatches(in: finalStr, range: .init(location: 0, length: finalStr.count), withTemplate: "") | |
} | |
if let regex = try? NSRegularExpression(pattern: "[.]$") { | |
finalStr = regex.stringByReplacingMatches(in: finalStr, range: .init(location: 0, length: finalStr.count), withTemplate: "") | |
} | |
} | |
return finalStr | |
} | |
var deformatedToPureString: String { | |
if self.match(type: .shitcoinPrice) { | |
let pattern = RegularType.shitcoinPrice.expression | |
let range = NSRange(self.startIndex..<self.endIndex, in: self) | |
if let regex = try? NSRegularExpression(pattern: pattern) { | |
let matches = regex.matches(in: self, range: range) | |
if matches.first != nil { | |
var captures: [String: String] = [:] | |
for match in matches { | |
// For each matched range, extract the named capture group | |
for name in ["zero", "decimal"] { | |
let matchRange = match.range(withName: name) | |
// Extract the substring matching the named capture group | |
if let substringRange = Range(matchRange, in: self) { | |
let capture = String(self[substringRange]) | |
captures[name] = capture | |
} | |
} | |
} | |
if let zeroCount = captures["zero"], | |
let decimal = captures["decimal"] { | |
let zeros = StringLiteralType(repeating: "0", count: Int(zeroCount) ?? 0) | |
return "0.\(zeros)\(decimal)" | |
} | |
} | |
} | |
} else if self.match(type: .scientificNotation) { | |
let pattern = #"^(?<symbol>[-+]?)(?<number>\d*)(?<decimal>\.([0-9]*))?e(?<notation>[+-]\d+)"# | |
let range = NSRange(self.startIndex..<self.endIndex, in: self) | |
if let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) { | |
let matches = regex.matches(in: self, range: range) | |
if matches.first != nil { | |
var captures: [String: String] = [:] | |
for match in matches { | |
// For each matched range, extract the named capture group | |
for name in ["symbol", "number", "decimal", "notation"] { | |
let matchRange = match.range(withName: name) | |
// Extract the substring matching the named capture group | |
if let substringRange = Range(matchRange, in: self) { | |
let capture = String(self[substringRange]) | |
captures[name] = capture | |
} | |
} | |
} | |
let symbol = captures["symbol"] ?? "" | |
if let number = captures["number"], | |
let notation = captures["notation"] { | |
let notationNumber = Int(notation) ?? 0 | |
var decimal = captures["decimal"] ?? "" | |
decimal = decimal.replacingOccurrences(of: ".", with: "") | |
if notationNumber > 0 { | |
if decimal.isEmpty { | |
let fString = number + String(repeating: "0", count: notationNumber) | |
return "\(symbol)\(fString)" | |
} else { | |
let len = decimal.count | |
if len > notationNumber { | |
let fString = number + decimal[0..<notationNumber] | |
return "\(symbol)\(fString)" | |
} else { | |
let dt = notationNumber - len | |
if dt > 0 { | |
let fString = number + decimal + String(repeating: "0", count: dt) | |
return "\(symbol)\(fString)" | |
} else if dt == 0 { | |
let fString = number + decimal | |
return "\(symbol)\(fString)" | |
} else { | |
let fString = number + decimal[0..<len] | |
return "\(symbol)\(fString)" | |
} | |
} | |
} | |
} else if notationNumber < 0 { | |
var fixNotation = abs(Int(notationNumber)) - 1 | |
if fixNotation < 0 { | |
fixNotation = 0 | |
} | |
let fString = "0." + String(repeating: "0", count: fixNotation) + number + decimal | |
return "\(symbol)\(fString)" | |
} | |
} | |
} | |
} | |
} | |
return self.replacingOccurrences(of: ",", with: "") | |
} | |
func formatedDecimal(validTailNumberCount: Int) -> String { | |
let string = self.deformatedToPureString | |
var validNumberCount = validTailNumberCount | |
if validNumberCount <= 0 { | |
validNumberCount = 1 | |
} | |
let amount = string.components(separatedBy: ".") | |
if amount.count == 2 { | |
let left = amount.first! | |
let right = amount.last! | |
let pattern = "^(?<validNumber>[0]*\\d{0,\(validNumberCount)}).*" | |
let range = NSRange(right.startIndex..<right.endIndex, in: right) | |
var matchRight = right | |
if let regex = try? NSRegularExpression(pattern: pattern) { | |
let matches = regex.matches(in: right, range: range) | |
if let match = matches.first { | |
let matchRange = match.range(withName: "validNumber") | |
// Extract the substring matching the named capture group | |
if let substringRange = Range(matchRange, in: right) { | |
let capture = String(right[substringRange]) | |
matchRight = capture | |
} | |
} | |
} | |
return (left + "." + matchRight).trimmingZeroDecimal | |
} else { | |
return string.trimmingZeroDecimal | |
} | |
} | |
func limitedDecimal(count: Int) -> String { | |
let string = self.deformatedToPureString | |
var validNumberCount = count | |
if validNumberCount <= 0 { | |
validNumberCount = 1 | |
} | |
let amount = string.components(separatedBy: ".") | |
if amount.count == 2 { | |
let left = amount.first! | |
let right = amount.last! | |
let pattern = "^(?<validNumber>\\d{0,\(validNumberCount)}).*" | |
let range = NSRange(right.startIndex..<right.endIndex, in: right) | |
var matchRight = right | |
if let regex = try? NSRegularExpression(pattern: pattern) { | |
let matches = regex.matches(in: right, range: range) | |
if let match = matches.first { | |
let matchRange = match.range(withName: "validNumber") | |
// Extract the substring matching the named capture group | |
if let substringRange = Range(matchRange, in: right) { | |
let capture = String(right[substringRange]) | |
matchRight = capture | |
} | |
} | |
} | |
return (left + "." + matchRight).trimmingZeroDecimal | |
} else { | |
return string.trimmingZeroDecimal | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage