Last active
January 24, 2024 08:13
-
-
Save MojtabaHs/c9168775b54f3a6cc478ed87a9104bd4 to your computer and use it in GitHub Desktop.
Converts between number and its abbreviation (1000 -> 1K -> 1000)
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
import Foundation | |
@dynamicMemberLookup | |
class NumberAbbreviationFormatter { | |
// MARK: - Internal properties | |
var formatter = NumberFormatter() | |
// MARK: - Static configurations | |
private let units = "KMBTPE" | |
.enumerated() | |
.map { (symbol: $0.element, value: pow(10, ($0.offset + 1) * 3)) } | |
// MARK: - Number to String conversion | |
func format(_ value: Int) -> String { | |
guard let unit = units.last(where: { $0.value.isLessThanOrEqualTo(Decimal(abs(value))) }) else { | |
return formatter.string(from: NSNumber(value: value)) ?? value.description | |
} | |
let factor = Decimal(value) / unit.value | |
let number = NSDecimalNumber(decimal: factor) as NSNumber | |
let formattedNumber = formatter.string(from: number) ?? number.description | |
return formattedNumber + String(unit.symbol).trimmingCharacters(in: .whitespaces) | |
} | |
// MARK: - String to Number conversion | |
func number(from string: String) -> Int? { | |
guard !string.isEmpty else { return nil } | |
guard string.last?.isNumber == false else { return formatter.number(from: string)?.intValue } | |
var string = string | |
let symbol = string.removeLast() | |
guard units.map(\.symbol).contains(symbol) else { return nil } | |
guard let number = formatter.number(from: string.trimmingCharacters(in: .whitespaces)) else { return nil } | |
let multiplier = units.first(where: { $0.symbol == symbol })?.value ?? 1 | |
let result = number.decimalValue * multiplier | |
return NSDecimalNumber(decimal: result).intValue | |
} | |
} | |
// MARK: - Dynamic member lookup conformance | |
/// Access to the internal formatter | |
extension NumberAbbreviationFormatter { | |
subscript<T>(dynamicMember keyPath: KeyPath<NumberFormatter, T>) -> T { | |
formatter[keyPath: keyPath] | |
} | |
subscript<T>(dynamicMember keyPath: WritableKeyPath<NumberFormatter, T>) -> T { | |
get { formatter[keyPath: keyPath] } | |
set { formatter[keyPath: keyPath] = newValue } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment