我正在尝试用 swift 语言编写一个 BMI 程序。我遇到了这个问题:如何将 String 转换为 Double?
在 Objective-C 中,我可以这样做:
double myDouble = [myString doubleValue];
但是我怎样才能在 Swift 语言中实现这一点呢?
Swift 2 更新 有新的可失败初始化程序允许您以更惯用和更安全的方式执行此操作(正如许多答案所指出的,NSString 的 double 值不是很安全,因为它为非数字值返回 0。这意味着 "foo"
和 "0"
的 doubleValue
相同。)
let myDouble = Double(myString)
这将返回一个可选值,因此在传入 "foo"
(其中 doubleValue
将返回 0)的情况下,可失败初始化程序将返回 nil
。您可以使用 guard
、if-let
或 map
来处理 Optional<Double>
原始帖子:您不需要像接受的答案所建议的那样使用 NSString 构造函数。您可以像这样简单地桥接它:
(swiftString as NSString).doubleValue
Swift 4.2+ 字符串加倍
您应该使用新的类型初始化器在 String 和数字类型(Double、Float、Int)之间进行转换。它将返回一个 Optional 类型(Double?),如果 String 不是数字,它将具有正确的值或 nil。
注意:不推荐使用 NSString doubleValue 属性,因为如果值无法转换(即:错误的用户输入),它会返回 0。
let lessPrecisePI = Float("3.14")
let morePrecisePI = Double("3.1415926536")
let invalidNumber = Float("alphabet") // nil, not a valid number
使用 if/let 解包值以使用它们
if let cost = Double(textField.text!) {
print("The user entered a value price of \(cost)")
} else {
print("Not a valid number: \(textField.text!)")
}
您可以使用 NumberFormatter
类转换格式化的数字和货币。
let formatter = NumberFormatter()
formatter.locale = Locale.current // USA: Locale(identifier: "en_US")
formatter.numberStyle = .decimal
let number = formatter.number(from: "9,999.99")
货币格式
let usLocale = Locale(identifier: "en_US")
let frenchLocale = Locale(identifier: "fr_FR")
let germanLocale = Locale(identifier: "de_DE")
let englishUKLocale = Locale(identifier: "en_GB") // United Kingdom
formatter.numberStyle = .currency
formatter.locale = usLocale
let usCurrency = formatter.number(from: "$9,999.99")
formatter.locale = frenchLocale
let frenchCurrency = formatter.number(from: "9999,99€")
// Note: "9 999,99€" fails with grouping separator
// Note: "9999,99 €" fails with a space before the €
formatter.locale = germanLocale
let germanCurrency = formatter.number(from: "9999,99€")
// Note: "9.999,99€" fails with grouping separator
formatter.locale = englishUKLocale
let englishUKCurrency = formatter.number(from: "£9,999.99")
阅读我的 blog post about converting String to Double types (and currency) 的更多信息。
Double(myString) ?? 0.0
以避免初始化错误
为了更加 Swift 的感觉,使用 NSFormatter()
避免强制转换为 NSString
,并在字符串不包含 Double
值时返回 nil
(例如,“test”不会返回 0.0
)。
let double = NSNumberFormatter().numberFromString(myString)?.doubleValue
或者,扩展 Swift 的 String
类型:
extension String {
func toDouble() -> Double? {
return NumberFormatter().number(from: self)?.doubleValue
}
}
并像 toInt()
一样使用它:
var myString = "4.2"
var myDouble = myString.toDouble()
这将返回一个可选的 Double?
,它必须被解包。
要么强制展开:
println("The value is \(myDouble!)") // prints: The value is 4.2
或使用 if let 语句:
if let myDouble = myDouble {
println("The value is \(myDouble)") // prints: The value is 4.2
}
更新:对于本地化,很容易将语言环境应用于 NSFormatter,如下所示:
let formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "fr_FR")
let double = formatter.numberFromString("100,25")
最后,如果您使用字符串中包含货币符号的货币,则可以在格式化程序上使用 NSNumberFormatterCurrencyStyle
。
这里的另一个选项是将其转换为 NSString
并使用它:
let string = NSString(string: mySwiftString)
string.doubleValue
(swiftString as NSString).doubleValue
这是一个扩展方法,它允许您在 Swift 字符串上简单地调用 doubleValue() 并获得双精度(首先是示例输出)
println("543.29".doubleValue())
println("543".doubleValue())
println(".29".doubleValue())
println("0.29".doubleValue())
println("-543.29".doubleValue())
println("-543".doubleValue())
println("-.29".doubleValue())
println("-0.29".doubleValue())
//prints
543.29
543.0
0.29
0.29
-543.29
-543.0
-0.29
-0.29
这是扩展方法:
extension String {
func doubleValue() -> Double
{
let minusAscii: UInt8 = 45
let dotAscii: UInt8 = 46
let zeroAscii: UInt8 = 48
var res = 0.0
let ascii = self.utf8
var whole = [Double]()
var current = ascii.startIndex
let negative = current != ascii.endIndex && ascii[current] == minusAscii
if (negative)
{
current = current.successor()
}
while current != ascii.endIndex && ascii[current] != dotAscii
{
whole.append(Double(ascii[current] - zeroAscii))
current = current.successor()
}
//whole number
var factor: Double = 1
for var i = countElements(whole) - 1; i >= 0; i--
{
res += Double(whole[i]) * factor
factor *= 10
}
//mantissa
if current != ascii.endIndex
{
factor = 0.1
current = current.successor()
while current != ascii.endIndex
{
res += Double(ascii[current] - zeroAscii) * factor
factor *= 0.1
current = current.successor()
}
}
if (negative)
{
res *= -1;
}
return res
}
}
没有错误检查,但如果需要,您可以添加它。
从 Swift 1.1 开始,您可以直接将 String
传递给 const char *
参数。
import Foundation
let str = "123.4567"
let num = atof(str) // -> 123.4567
atof("123.4567fubar") // -> 123.4567
如果您不喜欢已弃用的 atof
:
strtod("765.4321", nil) // -> 765.4321
一个警告:转换的行为与 NSString.doubleValue
不同。
atof
和 strtod
接受 0x
前缀的十六进制字符串:
atof("0xffp-2") // -> 63.75
atof("12.3456e+2") // -> 1,234.56
atof("nan") // -> (not a number)
atof("inf") // -> (+infinity)
如果您更喜欢 .doubleValue
行为,我们仍然可以使用 CFString
桥接:
let str = "0xff"
atof(str) // -> 255.0
strtod(str, nil) // -> 255.0
CFStringGetDoubleValue(str) // -> 0.0
(str as NSString).doubleValue // -> 0.0
NSString
。
在 Swift 2.0 中,最好的方法是避免像 Objective-C 开发人员那样思考。因此,您不应该“将字符串转换为 Double”,而应该“从字符串初始化 Double”。此处的 Apple 文档:https://developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Double_Structure/index.html#//apple_ref/swift/structctr/Double/s:FSdcFMSdFSSGSqSd_
它是一个可选的 init,因此您可以使用 nil 合并运算符 (??) 来设置默认值。例子:
let myDouble = Double("1.1") ?? 0.0
Double.init?(_ text: String)
在 Swift 2.0 中可用。你应该提到这一点。这里的其他答案不是因为人们像 Objective-C 开发人员那样思考,而是因为这个初始化程序在早期不可用。
我还没有看到我正在寻找的答案。我只是在这里发帖,以防它可以帮助任何人。仅当您不需要特定格式时,此答案才有效。
斯威夫特 3
extension String {
var toDouble: Double {
return Double(self) ?? 0.0
}
}
在 SWIFT 3 上,您可以使用:
if let myDouble = NumberFormatter().number(from: yourString)?.doubleValue {
print("My double: \(myDouble)")
}
注意: - 如果字符串包含除数字或适合区域设置的组或小数分隔符以外的任何字符,则解析将失败。 - 字符串中的任何前导或尾随空格分隔符都将被忽略。例如,字符串“5”、“5”和“5”都产生数字 5。
取自文档:https://developer.apple.com/reference/foundation/numberformatter/1408845-number
尝试这个:
var myDouble = myString.bridgeToObjectiveC().doubleValue
println(myDouble)
笔记
在 Beta 5 中删除。这不再有效?
这是基于@Ryu 的回答
只要您在使用点作为分隔符的国家/地区,他的解决方案就很棒。默认情况下 NSNumberFormatter
使用设备区域设置。因此,如果数字使用点作为分隔符(通常是这种情况),这将在所有使用逗号作为默认分隔符的国家(包括法国,如@PeterK. 提到)中失败。将此 NSNumberFormatter 的语言环境设置为 US 并因此使用点作为分隔符替换该行
return NSNumberFormatter().numberFromString(self)?.doubleValue
和
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
因此完整的代码变成
extension String {
func toDouble() -> Double? {
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
}
}
要使用它,只需调用 "Your text goes here".toDouble()
这将返回一个可选的 Double?
正如@Ryu 提到的,您可以强制展开:
println("The value is \(myDouble!)") // prints: The value is 4.2
或使用 if let
语句:
if let myDouble = myDouble {
println("The value is \(myDouble)") // prints: The value is 4.2
}
NumberFormatter().number(from: myString)?.doubleValue
斯威夫特 4
extension String {
func toDouble() -> Double? {
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "en_US_POSIX")
return numberFormatter.number(from: self)?.doubleValue
}
}
斯威夫特 4.0
尝试这个
let str:String = "111.11"
let tempString = (str as NSString).doubleValue
print("String:-",tempString)
斯威夫特:4和5
可能有两种方法可以做到这一点:
String -> Int -> Double: let strNumber = "314" if let intFromString = Int(strNumber){ let dobleFromInt = Double(intFromString) print(dobleFromInt) } String -> NSString -> Double let strNumber1 = "314" let NSstringFromString = NSString(string: strNumber1) 让 doubleFromNSString = NSstringFromString.doubleValue print(doubleFromNSString)
根据您对代码的需要,随意使用它。
请在操场上查看!
let sString = "236.86"
var dNumber = NSNumberFormatter().numberFromString(sString)
var nDouble = dNumber!
var eNumber = Double(nDouble) * 3.7
顺便说一句,在我的 Xcode 中
.toDouble() - 不存在
.doubleValue 从非数字字符串创建值 0.0...
正如已经指出的,实现这一点的最佳方法是直接铸造:
(myString as NSString).doubleValue
以此为基础,您可以制作一个漂亮的原生 Swift String 扩展:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
这允许您直接使用:
myString.doubleValue
它将为您执行铸造。如果 Apple 确实将 doubleValue
添加到本机字符串,您只需删除扩展名,其余代码将自动编译好!
1.
let strswift = "12"
let double = (strswift as NSString).doubleValue
2.
var strswift= "10.6"
var double : Double = NSString(string: strswift).doubleValue
可能对你有帮助。
带有可选语言环境的扩展
斯威夫特 2.2
extension String {
func toDouble(locale: NSLocale? = nil) -> Double? {
let formatter = NSNumberFormatter()
if let locale = locale {
formatter.locale = locale
}
return formatter.numberFromString(self)?.doubleValue
}
}
斯威夫特 3.1
extension String {
func toDouble(_ locale: Locale) -> Double {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = locale
formatter.usesGroupingSeparator = true
if let result = formatter.number(from: self)?.doubleValue {
return result
} else {
return 0
}
}
}
斯威夫特 3
要清楚,现在有一个默认方法:
public init?(_ text: String)` of `Double` class.
它可以用于所有课程。
let c = Double("-1.0")
let f = Double("0x1c.6")
let i = Double("inf")
, ETC。
或者你可以这样做:
var myDouble = Double((mySwiftString.text as NSString).doubleValue)
您可以使用 StringEx。它通过字符串到数字的转换扩展了 String
,包括 toDouble()
。
extension String {
func toDouble() -> Double?
}
它验证字符串,如果不能转换为双精度则失败。
例子:
import StringEx
let str = "123.45678"
if let num = str.toDouble() {
println("Number: \(num)")
} else {
println("Invalid string")
}
斯威夫特 4
extension String {
func toDouble() -> Double {
let nsString = self as NSString
return nsString.doubleValue
}
}
什么也有效:
// Init default Double variable
var scanned: Double()
let scanner = NSScanner(string: "String to Scan")
scanner.scanDouble(&scanned)
// scanned has now the scanned value if something was found.
在某些情况下使用 Scanner
是从字符串中提取数字的一种非常方便的方法。在解码和处理不同的数字格式和语言环境方面,它几乎与 NumberFormatter
一样强大。它可以提取具有不同小数和组分隔符的数字和货币。
import Foundation
// The code below includes manual fix for whitespaces (for French case)
let strings = ["en_US": "My salary is $9,999.99",
"fr_FR": "Mon salaire est 9 999,99€",
"de_DE": "Mein Gehalt ist 9999,99€",
"en_GB": "My salary is £9,999.99" ]
// Just for referce
let allPossibleDecimalSeparators = Set(Locale.availableIdentifiers.compactMap({ Locale(identifier: $0).decimalSeparator}))
print(allPossibleDecimalSeparators)
for str in strings {
let locale = Locale(identifier: str.key)
let valStr = str.value.filter{!($0.isWhitespace || $0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
但是,可以将分隔符视为单词分隔符存在一些问题。
// This doesn't work. `Scanner` just ignores grouping separators because scanner tends to seek for multiple values
// It just refuses to ignore spaces or commas for example.
let strings = ["en_US": "$9,999.99", "fr_FR": "9999,99€", "de_DE": "9999,99€", "en_GB": "£9,999.99" ]
for str in strings {
let locale = Locale(identifier: str.key)
let sc = Scanner(string: str.value)
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted.union(CharacterSet(charactersIn: locale.groupingSeparator ?? ""))
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: \(locale.groupingSeparator ?? "") . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// sc.scanDouble(representation: Scanner.NumberRepresentation) could help if there were .currency case
自动检测语言环境没有问题。请注意,字符串“Mon salaire est 9 999,99€”中法语语言环境中的 groupingSeparator 不是空格,尽管它可能会完全呈现为空格(这里不是)。这就是为什么下面的代码在没有 !$0.isWhitespace
字符被过滤的情况下可以正常工作的原因。
let stringsArr = ["My salary is $9,999.99",
"Mon salaire est 9 999,99€",
"Mein Gehalt ist 9.999,99€",
"My salary is £9,999.99" ]
let tagger = NSLinguisticTagger(tagSchemes: [.language], options: Int(NSLinguisticTagger.Options.init().rawValue))
for str in stringsArr {
tagger.string = str
let locale = Locale(identifier: tagger.dominantLanguage ?? "en")
let valStr = str.filter{!($0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// Also will fail if groupingSeparator == decimalSeparator (but don't think it's possible)
在 Swift 2.0 中使用此代码
let strWithFloat = "78.65"
let floatFromString = Double(strWithFloat)
如果字符串包含其他字符,例如:"27.8 °C"
、"52.523553 kM"
或 "Total: 349.0"
。
这适用于 Swift 4:
let anyString = "52.523553 kM"
let digitsCharacterSet = CharacterSet.init(charactersIn: "0123456789.")
let doubleResult = Double(anyString.components(separatedBy:digitsCharacterSet.inverted).joined())
注意! 这不适用于包含多个 .
的字符串,例如 "27.8 °C 3.5 kM"
我发现向 String 添加扩展名更具可读性,如下所示:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
然后你就可以编写你的代码:
myDouble = myString.doubleValue
我的问题是逗号,所以我这样解决:
extension String {
var doubleValue: Double {
return Double((self.replacingOccurrences(of: ",", with: ".") as NSString).doubleValue)
}
}
var stringValue = "55"
var convertToDouble = Double((stringValue as NSString).doubleValue)
我们可以使用由 myString.doubleValue 获得的 CDouble 值
Double?
(Optional<Double>
) 相对的- [NSString doubleValue]
的结果在 swift 中是Double
。这与 Swift 字符串函数toInt()
不同,后者返回Int?
并在文档中声明它“...仅接受与正则表达式“[-+]?[0-9]+”匹配的字符串。”.toInt()
会更好。然而,这更像是对如何做完全相同的事情的答案,但在 Swift 中。Double.init?(_ text: String)
可失败初始化程序。