@@ -631,15 +631,17 @@ extension Decimal {
631
631
}
632
632
}
633
633
634
- extension Decimal : CustomStringConvertible {
634
+ extension Decimal : CustomStringConvertible {
635
635
public init ? ( string: String , locale: Locale ? = nil ) {
636
636
let scan = Scanner ( string: string)
637
+ scan. locale = locale
637
638
var theDecimal = Decimal ( )
638
639
if !scan. scanDecimal ( & theDecimal) {
639
640
return nil
640
641
}
641
642
self = theDecimal
642
643
}
644
+
643
645
public var description : String {
644
646
if self . isNaN {
645
647
return " NaN "
@@ -2055,34 +2057,6 @@ fileprivate let pow10 = [
2055
2057
/*^39 is on 9 shorts. */
2056
2058
]
2057
2059
2058
- // Copied from Scanner.swift
2059
- private func decimalSep( _ locale: Locale ? ) -> String {
2060
- if let loc = locale {
2061
- if let sep = loc. _bridgeToObjectiveC ( ) . object ( forKey: . decimalSeparator) as? NSString {
2062
- return sep. _swiftObject
2063
- }
2064
- return " . "
2065
- } else {
2066
- return decimalSep ( Locale . current)
2067
- }
2068
- }
2069
-
2070
- // Copied from Scanner.swift
2071
- private func isADigit( _ ch: unichar ) -> Bool {
2072
- struct Local {
2073
- static let set = CharacterSet . decimalDigits
2074
- }
2075
- return Local . set. contains ( UnicodeScalar ( ch) !)
2076
- }
2077
-
2078
- // Copied from Scanner.swift
2079
- private func numericValue( _ ch: unichar ) -> Int {
2080
- if ( ch >= unichar ( unicodeScalarLiteral: " 0 " ) && ch <= unichar ( unicodeScalarLiteral: " 9 " ) ) {
2081
- return Int ( ch) - Int( unichar ( unicodeScalarLiteral: " 0 " ) )
2082
- } else {
2083
- return __CFCharDigitValue ( UniChar ( ch) )
2084
- }
2085
- }
2086
2060
2087
2061
// Could be silently inexact for float and double.
2088
2062
extension Scanner {
@@ -2094,78 +2068,66 @@ extension Scanner {
2094
2068
} else {
2095
2069
return false
2096
2070
}
2097
-
2098
2071
}
2099
2072
2100
2073
public func scanDecimal( ) -> Decimal ? {
2101
2074
2102
- var result = Decimal ( )
2103
-
2075
+ var result = Decimal . zero
2104
2076
let string = self . _scanString
2105
2077
let length = string. length
2106
2078
var buf = _NSStringBuffer ( string: string, start: self . _scanLocation, end: length)
2107
-
2108
- let ds_chars = decimalSep ( locale as? Locale ) . utf16
2109
- let ds = ds_chars [ ds_chars. startIndex]
2079
+ var tooBig = false
2080
+ let ds = ( locale as? Locale ?? Locale . current) . decimalSeparator? . first ?? Character ( " . " )
2110
2081
buf. skip ( _skipSet)
2111
2082
var neg = false
2083
+ var ok = false
2112
2084
2113
2085
if buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " + " ) {
2086
+ ok = true
2114
2087
neg = buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " )
2115
2088
buf. advance ( )
2116
2089
buf. skip ( _skipSet)
2117
2090
}
2118
- guard isADigit ( buf. currentCharacter) else {
2119
- return nil
2120
- }
2121
-
2122
- var tooBig = false
2123
2091
2124
2092
// build the mantissa
2125
- repeat {
2126
- let numeral = numericValue ( buf. currentCharacter)
2127
- if numeral == - 1 {
2128
- break
2129
- }
2130
-
2093
+ while let numeral = decimalValue ( buf. currentCharacter) {
2094
+ ok = true
2131
2095
if tooBig || multiplyBy10 ( & result, andAdd: numeral) != . noError {
2132
2096
tooBig = true
2133
2097
if result. _exponent == Int32 ( Int8 . max) {
2134
2098
repeat {
2135
2099
buf. advance ( )
2136
- } while isADigit ( buf. currentCharacter)
2100
+ } while decimalValue ( buf. currentCharacter) != nil
2137
2101
return Decimal . nan
2138
2102
}
2139
2103
result. _exponent += 1
2140
2104
}
2141
2105
buf. advance ( )
2142
- } while isADigit ( buf . currentCharacter )
2106
+ }
2143
2107
2144
2108
// get the decimal point
2145
- if buf. currentCharacter == ds {
2109
+ if let us = UnicodeScalar ( buf. currentCharacter) , Character ( us) == ds {
2110
+ ok = true
2146
2111
buf. advance ( )
2147
2112
// continue to build the mantissa
2148
- repeat {
2149
- let numeral = numericValue ( buf. currentCharacter)
2150
- if numeral == - 1 {
2151
- break
2152
- }
2113
+ while let numeral = decimalValue ( buf. currentCharacter) {
2153
2114
if tooBig || multiplyBy10 ( & result, andAdd: numeral) != . noError {
2154
2115
tooBig = true
2155
2116
} else {
2156
2117
if result. _exponent == Int32 ( Int8 . min) {
2157
2118
repeat {
2158
2119
buf. advance ( )
2159
- } while isADigit ( buf. currentCharacter)
2120
+ } while decimalValue ( buf. currentCharacter) != nil
2160
2121
return Decimal . nan
2161
2122
}
2162
2123
result. _exponent -= 1
2163
2124
}
2164
2125
buf. advance ( )
2165
- } while isADigit ( buf . currentCharacter )
2126
+ }
2166
2127
}
2167
2128
2168
2129
if buf. currentCharacter == unichar ( unicodeScalarLiteral: " e " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " E " ) {
2130
+ ok = true
2169
2131
var exponentIsNegative = false
2170
2132
var exponent : Int32 = 0
2171
2133
@@ -2177,18 +2139,14 @@ extension Scanner {
2177
2139
buf. advance ( )
2178
2140
}
2179
2141
2180
- repeat {
2181
- let numeral = numericValue ( buf. currentCharacter)
2182
- if numeral == - 1 {
2183
- break
2184
- }
2142
+ while let numeral = decimalValue ( buf. currentCharacter) {
2185
2143
exponent = 10 * exponent + Int32( numeral)
2186
2144
guard exponent <= 2 * Int32( Int8 . max) else {
2187
2145
return Decimal . nan
2188
2146
}
2189
2147
2190
2148
buf. advance ( )
2191
- } while isADigit ( buf . currentCharacter )
2149
+ }
2192
2150
2193
2151
if exponentIsNegative {
2194
2152
exponent = - exponent
@@ -2200,6 +2158,9 @@ extension Scanner {
2200
2158
result. _exponent = exponent
2201
2159
}
2202
2160
2161
+ // No valid characters have been seen upto this point so error out.
2162
+ guard ok == true else { return nil }
2163
+
2203
2164
result. isNegative = neg
2204
2165
2205
2166
// if we get to this point, and have NaN, then the input string was probably "-0"
@@ -2212,6 +2173,12 @@ extension Scanner {
2212
2173
self . _scanLocation = buf. location
2213
2174
return result
2214
2175
}
2176
+
2177
+ // Copied from Scanner.swift
2178
+ private func decimalValue( _ ch: unichar ) -> Int ? {
2179
+ guard let s = UnicodeScalar ( ch) , s. isASCII else { return nil }
2180
+ return Character ( s) . wholeNumberValue
2181
+ }
2215
2182
}
2216
2183
2217
2184
extension Decimal : Codable {
0 commit comments