Skip to content

Instantly share code, notes, and snippets.

@kk-vv
Last active May 16, 2024 07:18
Show Gist options
  • Save kk-vv/87b16a88a9ffd813f998287f4b94533f to your computer and use it in GitHub Desktop.
Save kk-vv/87b16a88a9ffd813f998287f4b94533f to your computer and use it in GitHub Desktop.
Shitcoin price format eg. 0.0{6}4518
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
}
}
}
@kk-vv
Copy link
Author

kk-vv commented Feb 2, 2024

  • Usage
"0.000000451864".formattedPrice // 0.0{6}4518

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment