blob: 168c06eaeb8c51c39915ac270455dd8f442707e4 [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016, 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
import CoreFoundation
extension NumberFormatter {
public enum Style : UInt {
case none = 0
case decimal = 1
case currency = 2
case percent = 3
case scientific = 4
case spellOut = 5
case ordinal = 6
case currencyISOCode = 8 // 7 is not used
case currencyPlural = 9
case currencyAccounting = 10
}
public enum PadPosition : UInt {
case beforePrefix
case afterPrefix
case beforeSuffix
case afterSuffix
}
public enum RoundingMode : UInt {
case ceiling
case floor
case down
case up
case halfEven
case halfDown
case halfUp
}
}
open class NumberFormatter : Formatter {
typealias CFType = CFNumberFormatter
private var _currentCfFormatter: CFType?
private var _cfFormatter: CFType {
if let obj = _currentCfFormatter {
return obj
} else {
#if os(macOS) || os(iOS)
let numberStyle = CFNumberFormatterStyle(rawValue: CFIndex(self.numberStyle.rawValue))!
#else
let numberStyle = CFNumberFormatterStyle(self.numberStyle.rawValue)
#endif
let obj = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale._cfObject, numberStyle)!
_setFormatterAttributes(obj)
if _positiveFormat != nil || _negativeFormat != nil {
var format = _positiveFormat ?? "#"
if let negative = _negativeFormat {
format.append(";")
format.append(negative)
}
CFNumberFormatterSetFormat(obj, format._cfObject)
}
_currentCfFormatter = obj
return obj
}
}
// this is for NSUnitFormatter
open var formattingContext: Context = .unknown // default is NSFormattingContextUnknown
@available(*, unavailable, renamed: "number(from:)")
func getObjectValue(_ obj: UnsafeMutablePointer<AnyObject?>?,
for string: String,
range rangep: UnsafeMutablePointer<NSRange>?) throws {
NSUnsupported()
}
open override func string(for obj: Any) -> String? {
//we need to allow Swift's numeric types here - Int, Double et al.
guard let number = __SwiftValue.store(obj) as? NSNumber else { return nil }
return string(from: number)
}
// Even though NumberFormatter responds to the usual Formatter methods,
// here are some convenience methods which are a little more obvious.
open func string(from number: NSNumber) -> String? {
return CFNumberFormatterCreateStringWithNumber(kCFAllocatorSystemDefault, _cfFormatter, number._cfObject)._swiftObject
}
open func number(from string: String) -> NSNumber? {
var range = CFRange(location: 0, length: string.length)
let number = withUnsafeMutablePointer(to: &range) { (rangePointer: UnsafeMutablePointer<CFRange>) -> NSNumber? in
#if os(macOS) || os(iOS)
let parseOption = allowsFloats ? 0 : CFNumberFormatterOptionFlags.parseIntegersOnly.rawValue
#else
let parseOption = allowsFloats ? 0 : CFOptionFlags(kCFNumberFormatterParseIntegersOnly)
#endif
let result = CFNumberFormatterCreateNumberFromString(kCFAllocatorSystemDefault, _cfFormatter, string._cfObject, rangePointer, parseOption)
return result?._nsObject
}
return number
}
open class func localizedString(from num: NSNumber, number nstyle: Style) -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = nstyle
return numberFormatter.string(for: num)!
}
private func _reset() {
_currentCfFormatter = nil
}
private func _setFormatterAttributes(_ formatter: CFNumberFormatter) {
if numberStyle == .currency {
let symbol = _currencySymbol ?? _currencyCode ?? locale.currencySymbol ?? locale.currencyCode
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterCurrencySymbol, value: symbol?._cfObject)
}
if numberStyle == .currencyISOCode {
let code = _currencyCode ?? _currencySymbol ?? locale.currencyCode ?? locale.currencySymbol
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterCurrencyCode, value: code?._cfObject)
}
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterDecimalSeparator, value: _decimalSeparator?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterCurrencyDecimalSeparator, value: _currencyDecimalSeparator?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterAlwaysShowDecimalSeparator, value: _alwaysShowsDecimalSeparator._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterGroupingSeparator, value: _groupingSeparator?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterUseGroupingSeparator, value: usesGroupingSeparator._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPercentSymbol, value: _percentSymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterZeroSymbol, value: _zeroSymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterNaNSymbol, value: _notANumberSymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterInfinitySymbol, value: _positiveInfinitySymbol._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMinusSign, value: _minusSign?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPlusSign, value: _plusSign?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterExponentSymbol, value: _exponentSymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMinIntegerDigits, value: _minimumIntegerDigits?._bridgeToObjectiveC()._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMaxIntegerDigits, value: _maximumIntegerDigits?._bridgeToObjectiveC()._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMinFractionDigits, value: _minimumFractionDigits?._bridgeToObjectiveC()._cfObject)
if minimumFractionDigits <= 0 {
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMaxFractionDigits, value: maximumFractionDigits._bridgeToObjectiveC()._cfObject)
}
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterGroupingSize, value: groupingSize._bridgeToObjectiveC()._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterSecondaryGroupingSize, value: _secondaryGroupingSize._bridgeToObjectiveC()._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterRoundingMode, value: _roundingMode.rawValue._bridgeToObjectiveC()._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterRoundingIncrement, value: _roundingIncrement?._cfObject)
var width: Int = 0
CFNumberGetValue(_formatWidth._bridgeToObjectiveC()._cfObject, kCFNumberLongType, &width)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterFormatWidth, value: _formatWidth._bridgeToObjectiveC()._cfObject)
if width > 0 {
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPaddingCharacter, value: _paddingCharacter?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPaddingPosition, value: _paddingPosition.rawValue._bridgeToObjectiveC()._cfObject)
} else {
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPaddingCharacter, value: ""._cfObject)
}
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMultiplier, value: multiplier?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPositivePrefix, value: _positivePrefix?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPositiveSuffix, value: _positiveSuffix?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterNegativePrefix, value: _negativePrefix?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterNegativeSuffix, value: _negativeSuffix?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPerMillSymbol, value: _percentSymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterInternationalCurrencySymbol, value: _internationalCurrencySymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterCurrencyGroupingSeparator, value: _currencyGroupingSeparator?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterIsLenient, value: _lenient._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterUseSignificantDigits, value: usesSignificantDigits._cfObject)
if usesSignificantDigits {
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMinSignificantDigits, value: minimumSignificantDigits._bridgeToObjectiveC()._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMaxSignificantDigits, value: maximumSignificantDigits._bridgeToObjectiveC()._cfObject)
}
}
private func _setFormatterAttribute(_ formatter: CFNumberFormatter, attributeName: CFString, value: AnyObject?) {
if let value = value {
CFNumberFormatterSetProperty(formatter, attributeName, value)
}
}
private func _getFormatterAttribute(_ formatter: CFNumberFormatter, attributeName: CFString) -> String? {
return CFNumberFormatterCopyProperty(formatter, attributeName) as? String
}
// Attributes of a NumberFormatter. Many attributes have default values but if they are set by the caller
// the new value needs to be retained even if the .numberStyle is changed. Attributes are backed by an optional
// to indicate to use the default value (if nil) or the caller-supplied value (if not nil).
private func defaultMinimumIntegerDigits() -> Int {
switch numberStyle {
case .none, .ordinal, .spellOut, .currencyPlural, .scientific:
return 0
case .currency, .currencyISOCode, .currencyAccounting, .decimal, .percent:
return 1
}
}
private func defaultMaximumIntegerDigits() -> Int {
switch numberStyle {
case .none:
return 42
case .ordinal, .spellOut, .currencyPlural:
return 0
case .currency, .currencyISOCode, .currencyAccounting, .decimal, .percent:
return 2_000_000_000
case .scientific:
return 1
}
}
private func defaultMinimumFractionDigits() -> Int {
switch numberStyle {
case .none, .ordinal, .spellOut, .currencyPlural, .decimal, .percent, .scientific:
return 0
case .currency, .currencyISOCode, .currencyAccounting:
return 2
}
}
private func defaultMaximumFractionDigits() -> Int {
switch numberStyle {
case .none, .ordinal, .spellOut, .currencyPlural, .percent, .scientific:
return 0
case .currency, .currencyISOCode, .currencyAccounting:
return 2
case .decimal:
return 3
}
}
private func defaultMinimumSignificantDigits() -> Int {
switch numberStyle {
case .ordinal, .spellOut, .currencyPlural:
return 0
case .currency, .none, .currencyISOCode, .currencyAccounting, .decimal, .percent, .scientific:
return 1
}
}
private func defaultMaximumSignificantDigits() -> Int {
switch numberStyle {
case .none, .currency, .currencyISOCode, .currencyAccounting, .decimal, .percent, .scientific:
return 6
case .ordinal, .spellOut, .currencyPlural:
return 0
}
}
private func defaultUsesGroupingSeparator() -> Bool {
switch numberStyle {
case .none, .scientific, .spellOut, .ordinal, .currencyPlural:
return false
case .decimal, .currency, .percent, .currencyAccounting, .currencyISOCode:
return true
}
}
private func defaultGroupingSize() -> Int {
switch numberStyle {
case .none, .ordinal, .spellOut, .currencyPlural, .scientific:
return 0
case .currency, .currencyISOCode, .currencyAccounting, .decimal, .percent:
return 3
}
}
private func defaultMultiplier() -> NSNumber? {
switch numberStyle {
case .percent: return NSNumber(100)
default: return nil
}
}
private var _numberStyle: Style = .none
open var numberStyle: Style {
get {
return _numberStyle
}
set {
_reset()
_numberStyle = newValue
}
}
private var _locale: Locale = Locale.current
/*@NSCopying*/ open var locale: Locale! {
get {
return _locale
}
set {
_reset()
_locale = newValue
}
}
private var _generatesDecimalNumbers: Bool = false
open var generatesDecimalNumbers: Bool {
get {
return _generatesDecimalNumbers
}
set {
_reset()
_generatesDecimalNumbers = newValue
}
}
private var _textAttributesForNegativeValues: [String : Any]?
open var textAttributesForNegativeValues: [String : Any]? {
get {
return _textAttributesForNegativeValues
}
set {
_reset()
_textAttributesForNegativeValues = newValue
}
}
private var _textAttributesForPositiveValues: [String : Any]?
open var textAttributesForPositiveValues: [String : Any]? {
get {
return _textAttributesForPositiveValues
}
set {
_reset()
_textAttributesForPositiveValues = newValue
}
}
private var _allowsFloats: Bool = true
open var allowsFloats: Bool {
get {
return _allowsFloats
}
set {
_reset()
_allowsFloats = newValue
}
}
private var _decimalSeparator: String!
open var decimalSeparator: String! {
get {
return _decimalSeparator ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterDecimalSeparator)
}
set {
_reset()
_decimalSeparator = newValue
}
}
private var _alwaysShowsDecimalSeparator: Bool = false
open var alwaysShowsDecimalSeparator: Bool {
get {
return _alwaysShowsDecimalSeparator
}
set {
_reset()
_alwaysShowsDecimalSeparator = newValue
}
}
private var _currencyDecimalSeparator: String!
open var currencyDecimalSeparator: String! {
get {
return _currencyDecimalSeparator ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterCurrencyDecimalSeparator)
}
set {
_reset()
_currencyDecimalSeparator = newValue
}
}
private var _usesGroupingSeparator: Bool?
open var usesGroupingSeparator: Bool {
get {
return _usesGroupingSeparator ?? defaultUsesGroupingSeparator()
}
set {
_reset()
_usesGroupingSeparator = newValue
}
}
private var _groupingSeparator: String!
open var groupingSeparator: String! {
get {
return _groupingSeparator ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterGroupingSeparator)
}
set {
_reset()
_groupingSeparator = newValue
}
}
private var _zeroSymbol: String?
open var zeroSymbol: String? {
get {
return _zeroSymbol
}
set {
_reset()
_zeroSymbol = newValue
}
}
private var _textAttributesForZero: [String : Any]?
open var textAttributesForZero: [String : Any]? {
get {
return _textAttributesForZero
}
set {
_reset()
_textAttributesForZero = newValue
}
}
private var _nilSymbol: String = ""
open var nilSymbol: String {
get {
return _nilSymbol
}
set {
_reset()
_nilSymbol = newValue
}
}
private var _textAttributesForNil: [String : Any]?
open var textAttributesForNil: [String : Any]? {
get {
return _textAttributesForNil
}
set {
_reset()
_textAttributesForNil = newValue
}
}
private var _notANumberSymbol: String!
open var notANumberSymbol: String! {
get {
return _notANumberSymbol ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterNaNSymbol)
}
set {
_reset()
_notANumberSymbol = newValue
}
}
private var _textAttributesForNotANumber: [String : Any]?
open var textAttributesForNotANumber: [String : Any]? {
get {
return _textAttributesForNotANumber
}
set {
_reset()
_textAttributesForNotANumber = newValue
}
}
private var _positiveInfinitySymbol: String = "+∞"
open var positiveInfinitySymbol: String {
get {
return _positiveInfinitySymbol
}
set {
_reset()
_positiveInfinitySymbol = newValue
}
}
private var _textAttributesForPositiveInfinity: [String : Any]?
open var textAttributesForPositiveInfinity: [String : Any]? {
get {
return _textAttributesForPositiveInfinity
}
set {
_reset()
_textAttributesForPositiveInfinity = newValue
}
}
private var _negativeInfinitySymbol: String = "-∞"
open var negativeInfinitySymbol: String {
get {
return _negativeInfinitySymbol
}
set {
_reset()
_negativeInfinitySymbol = newValue
}
}
private var _textAttributesForNegativeInfinity: [String : Any]?
open var textAttributesForNegativeInfinity: [String : Any]? {
get {
return _textAttributesForNegativeInfinity
}
set {
_reset()
_textAttributesForNegativeInfinity = newValue
}
}
private var _positivePrefix: String!
open var positivePrefix: String! {
get {
return _positivePrefix ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterPositivePrefix)
}
set {
_reset()
_positivePrefix = newValue
}
}
private var _positiveSuffix: String!
open var positiveSuffix: String! {
get {
return _positiveSuffix ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterPositiveSuffix)
}
set {
_reset()
_positiveSuffix = newValue
}
}
private var _negativePrefix: String!
open var negativePrefix: String! {
get {
return _negativePrefix ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterNegativePrefix)
}
set {
_reset()
_negativePrefix = newValue
}
}
private var _negativeSuffix: String!
open var negativeSuffix: String! {
get {
return _negativeSuffix ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterNegativeSuffix)
}
set {
_reset()
_negativeSuffix = newValue
}
}
private var _currencyCode: String!
open var currencyCode: String! {
get {
return _currencyCode ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterCurrencyCode)
}
set {
_reset()
_currencyCode = newValue
}
}
private var _currencySymbol: String!
open var currencySymbol: String! {
get {
return _currencySymbol ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterCurrencySymbol)
}
set {
_reset()
_currencySymbol = newValue
}
}
private var _internationalCurrencySymbol: String!
open var internationalCurrencySymbol: String! {
get {
return _internationalCurrencySymbol ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterInternationalCurrencySymbol)
}
set {
_reset()
_internationalCurrencySymbol = newValue
}
}
private var _percentSymbol: String!
open var percentSymbol: String! {
get {
return _percentSymbol ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterPercentSymbol) ?? "%"
}
set {
_reset()
_percentSymbol = newValue
}
}
private var _perMillSymbol: String!
open var perMillSymbol: String! {
get {
return _perMillSymbol ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterPerMillSymbol)
}
set {
_reset()
_perMillSymbol = newValue
}
}
private var _minusSign: String!
open var minusSign: String! {
get {
return _minusSign ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterMinusSign)
}
set {
_reset()
_minusSign = newValue
}
}
private var _plusSign: String!
open var plusSign: String! {
get {
return _plusSign ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterPlusSign)
}
set {
_reset()
_plusSign = newValue
}
}
private var _exponentSymbol: String!
open var exponentSymbol: String! {
get {
return _exponentSymbol ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterExponentSymbol)
}
set {
_reset()
_exponentSymbol = newValue
}
}
private var _groupingSize: Int?
open var groupingSize: Int {
get {
return _groupingSize ?? defaultGroupingSize()
}
set {
_reset()
_groupingSize = newValue
}
}
private var _secondaryGroupingSize: Int = 0
open var secondaryGroupingSize: Int {
get {
return _secondaryGroupingSize
}
set {
_reset()
_secondaryGroupingSize = newValue
}
}
private var _multiplier: NSNumber?
/*@NSCopying*/ open var multiplier: NSNumber? {
get {
return _multiplier ?? defaultMultiplier()
}
set {
_reset()
_multiplier = newValue
}
}
private var _formatWidth: Int = 0
open var formatWidth: Int {
get {
return _formatWidth
}
set {
_reset()
_formatWidth = newValue
}
}
private var _paddingCharacter: String! = " "
open var paddingCharacter: String! {
get {
return _paddingCharacter ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterPaddingCharacter)
}
set {
_reset()
_paddingCharacter = newValue
}
}
private var _paddingPosition: PadPosition = .beforePrefix
open var paddingPosition: PadPosition {
get {
return _paddingPosition
}
set {
_reset()
_paddingPosition = newValue
}
}
private var _roundingMode: RoundingMode = .halfEven
open var roundingMode: RoundingMode {
get {
return _roundingMode
}
set {
_reset()
_roundingMode = newValue
}
}
private var _roundingIncrement: NSNumber! = 0
/*@NSCopying*/ open var roundingIncrement: NSNumber! {
get {
return _roundingIncrement
}
set {
_reset()
_roundingIncrement = newValue
}
}
// Use an optional for _minimumIntegerDigits to track if the value is
// set BEFORE the .numberStyle is changed. This allows preserving a setting
// of 0.
private var _minimumIntegerDigits: Int?
open var minimumIntegerDigits: Int {
get {
return _minimumIntegerDigits ?? defaultMinimumIntegerDigits()
}
set {
_reset()
_minimumIntegerDigits = newValue
}
}
private var _maximumIntegerDigits: Int?
open var maximumIntegerDigits: Int {
get {
return _maximumIntegerDigits ?? defaultMaximumIntegerDigits()
}
set {
_reset()
_maximumIntegerDigits = newValue
}
}
private var _minimumFractionDigits: Int?
open var minimumFractionDigits: Int {
get {
return _minimumFractionDigits ?? defaultMinimumFractionDigits()
}
set {
_reset()
_minimumFractionDigits = newValue
}
}
private var _maximumFractionDigits: Int?
open var maximumFractionDigits: Int {
get {
return _maximumFractionDigits ?? defaultMaximumFractionDigits()
}
set {
_reset()
_maximumFractionDigits = newValue
}
}
private var _minimum: NSNumber?
/*@NSCopying*/ open var minimum: NSNumber? {
get {
return _minimum
}
set {
_reset()
_minimum = newValue
}
}
private var _maximum: NSNumber?
/*@NSCopying*/ open var maximum: NSNumber? {
get {
return _maximum
}
set {
_reset()
_maximum = newValue
}
}
private var _currencyGroupingSeparator: String!
open var currencyGroupingSeparator: String! {
get {
return _currencyGroupingSeparator ?? _getFormatterAttribute(_cfFormatter, attributeName: kCFNumberFormatterCurrencyGroupingSeparator)
}
set {
_reset()
_currencyGroupingSeparator = newValue
}
}
private var _lenient: Bool = false
open var isLenient: Bool {
get {
return _lenient
}
set {
_reset()
_lenient = newValue
}
}
private var _usesSignificantDigits: Bool?
open var usesSignificantDigits: Bool {
get {
return _usesSignificantDigits ?? false
}
set {
_reset()
_usesSignificantDigits = newValue
}
}
private var _minimumSignificantDigits: Int?
open var minimumSignificantDigits: Int {
get {
return _minimumSignificantDigits ?? defaultMinimumSignificantDigits()
}
set {
_reset()
_usesSignificantDigits = true
_minimumSignificantDigits = newValue
}
}
private var _maximumSignificantDigits: Int?
open var maximumSignificantDigits: Int {
get {
return _maximumSignificantDigits ?? defaultMaximumSignificantDigits()
}
set {
_reset()
_usesSignificantDigits = true
_maximumSignificantDigits = newValue
}
}
private var _partialStringValidationEnabled: Bool = false
open var isPartialStringValidationEnabled: Bool {
get {
return _partialStringValidationEnabled
}
set {
_reset()
_partialStringValidationEnabled = newValue
}
}
private var _hasThousandSeparators: Bool = false
open var hasThousandSeparators: Bool {
get {
return _hasThousandSeparators
}
set {
_reset()
_hasThousandSeparators = newValue
}
}
private var _thousandSeparator: String!
open var thousandSeparator: String! {
get {
return _thousandSeparator
}
set {
_reset()
_thousandSeparator = newValue
}
}
private var _localizesFormat: Bool = true
open var localizesFormat: Bool {
get {
return _localizesFormat
}
set {
_reset()
_localizesFormat = newValue
}
}
private func getFormatterComponents() -> (String?, String?) {
guard let format = CFNumberFormatterGetFormat(_cfFormatter)?._swiftObject else {
return (nil, nil)
}
let components = format.components(separatedBy: ";")
let positive = _positiveFormat ?? components.first ?? "#"
let negative = _negativeFormat ?? components.last ?? "#"
return (positive, negative)
}
private func getZeroFormat() -> String {
return string(from: 0) ?? "0"
}
open var format: String {
get {
let (p, n) = getFormatterComponents()
let z = _zeroSymbol ?? getZeroFormat()
return "\(p ?? "(null)");\(z);\(n ?? "(null)")"
}
set {
// Special case empty string
if newValue == "" {
_positiveFormat = ""
_negativeFormat = "-"
_zeroSymbol = "0"
_reset()
} else {
let components = newValue.components(separatedBy: ";")
let count = components.count
guard count <= 3 else { return }
_reset()
_positiveFormat = components.first ?? ""
if count == 1 {
_negativeFormat = "-\(_positiveFormat ?? "")"
}
else if count == 2 {
_negativeFormat = components[1]
_zeroSymbol = getZeroFormat()
}
else if count == 3 {
_zeroSymbol = components[1]
_negativeFormat = components[2]
}
if _negativeFormat == nil {
_negativeFormat = getFormatterComponents().1
}
if _zeroSymbol == nil {
_zeroSymbol = getZeroFormat()
}
}
}
}
private var _positiveFormat: String!
open var positiveFormat: String! {
get {
return getFormatterComponents().0
}
set {
_reset()
_positiveFormat = newValue
}
}
private var _negativeFormat: String!
open var negativeFormat: String! {
get {
return getFormatterComponents().1
}
set {
_reset()
_negativeFormat = newValue
}
}
private var _attributedStringForZero: NSAttributedString = NSAttributedString(string: "0")
/*@NSCopying*/ open var attributedStringForZero: NSAttributedString {
get {
return _attributedStringForZero
}
set {
_reset()
_attributedStringForZero = newValue
}
}
private var _attributedStringForNil: NSAttributedString = NSAttributedString(string: "")
/*@NSCopying*/ open var attributedStringForNil: NSAttributedString {
get {
return _attributedStringForNil
}
set {
_reset()
_attributedStringForNil = newValue
}
}
private var _attributedStringForNotANumber: NSAttributedString = NSAttributedString(string: "NaN")
/*@NSCopying*/ open var attributedStringForNotANumber: NSAttributedString {
get {
return _attributedStringForNotANumber
}
set {
_reset()
_attributedStringForNotANumber = newValue
}
}
private var _roundingBehavior: NSDecimalNumberHandler = NSDecimalNumberHandler.default
/*@NSCopying*/ open var roundingBehavior: NSDecimalNumberHandler {
get {
return _roundingBehavior
}
set {
_reset()
_roundingBehavior = newValue
}
}
}