简体   繁体   English

Swift - 如何将字符串转换为双精度

[英]Swift - How to convert String to Double

I'm trying to write a BMI program in swift language.我正在尝试用 swift 语言编写一个 BMI 程序。 And I got this problem: how to convert a String to a Double?我遇到了这个问题:如何将 String 转换为 Double?

In Objective-C, I can do like this:在 Objective-C 中,我可以这样做:

double myDouble = [myString doubleValue];

But how can I achieve this in Swift language?但是我怎样才能用 Swift 语言实现这一点呢?

Swift 2 Update There are new failable initializers that allow you to do this in more idiomatic and safe way (as many answers have noted, NSString's double value is not very safe because it returns 0 for non number values. This means that the doubleValue of "foo" and "0" are the same.) Swift 2 更新有新的可失败初始化器,允许您以更惯用和安全的方式执行此操作(正如许多答案所指出的,NSString 的 double 值不是很安全,因为它对于非数字值返回 0。这意味着"foo"doubleValue "foo""0"是相同的。)

let myDouble = Double(myString)

This returns an optional, so in cases like passing in "foo" where doubleValue would have returned 0, the failable intializer will return nil .这将返回一个可选值,因此在传入"foo"类的情况下, doubleValue将返回 0,可失败的初始化器将返回nil You can use a guard , if-let , or map to handle the Optional<Double>您可以使用guardif-letmap来处理Optional<Double>

Original Post: You don't need to use the NSString constructor like the accepted answer proposes.原帖:您不需要像接受的答案建议那样使用 NSString 构造函数。 You can simply bridge it like this:你可以像这样简单地桥接它:

(swiftString as NSString).doubleValue

Swift 4.2+ String to Double Swift 4.2+ 字符串转双

You should use the new type initializers to convert between String and numeric types (Double, Float, Int).您应该使用新的类型初始值设定项在字符串和数字类型(Double、Float、Int)之间进行转换。 It'll return an Optional type (Double?) which will have the correct value or nil if the String was not a number.它将返回一个 Optional 类型(Double?),如果 String 不是数字,它将具有正确的值或 nil。

Note: The NSString doubleValue property is not recommended because it returns 0 if the value cannot be converted (ie: bad user input).注意:不推荐使用 NSString doubleValue 属性,因为如果值无法转换(即:错误的用户输入),它会返回 0。

let lessPrecisePI = Float("3.14")

let morePrecisePI = Double("3.1415926536")
let invalidNumber = Float("alphabet") // nil, not a valid number

Unwrap the values to use them using if/let使用 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!)")
}

You can convert formatted numbers and currency using the NumberFormatter class.您可以使用NumberFormatter类转换格式化的数字和货币。

let formatter = NumberFormatter()
formatter.locale = Locale.current // USA: Locale(identifier: "en_US")
formatter.numberStyle = .decimal
let number = formatter.number(from: "9,999.99")

Currency formats货币格式

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")

Read more on my blog post about converting String to Double types (and currency) .在我的博客文章中阅读有关将 String 转换为 Double 类型(和货币)的更多信息

For a little more Swift feeling, using NSFormatter() avoids casting to NSString , and returns nil when the string does not contain a Double value (eg "test" will not return 0.0 ).为了获得更多的 Swift 感觉,使用NSFormatter()避免强制转换为NSString ,并在字符串不包含Double值时返回nil (例如,“test”不会返回0.0 )。

let double = NSNumberFormatter().numberFromString(myString)?.doubleValue

Alternatively, extending Swift's String type:或者,扩展 Swift 的String类型:

extension String {
    func toDouble() -> Double? {
        return NumberFormatter().number(from: self)?.doubleValue
    }
}

and use it like toInt() :并像toInt()一样使用它:

var myString = "4.2"
var myDouble = myString.toDouble()

This returns an optional Double?这将返回一个可选的Double? which has to be unwrapped.必须解开。

Either with forced unwrapping:要么强制解包:

println("The value is \(myDouble!)") // prints: The value is 4.2

or with an if let statement:或使用 if let 语句:

if let myDouble = myDouble {
    println("The value is \(myDouble)") // prints: The value is 4.2
}

Update: For localization, it is very easy to apply locales to the NSFormatter as follows:更新:对于本地化,将语言环境应用到 NSFormatter 非常容易,如下所示:

let formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "fr_FR")
let double = formatter.numberFromString("100,25")

Finally, you can use NSNumberFormatterCurrencyStyle on the formatter if you are working with currencies where the string contains the currency symbol.最后,如果您使用字符串包含货币符号的货币,您可以在格式化程序上使用NSNumberFormatterCurrencyStyle

Another option here is converting this to an NSString and using that:这里的另一个选择是将其转换为NSString并使用它:

let string = NSString(string: mySwiftString)
string.doubleValue

Here's an extension method that allows you to simply call doubleValue() on a Swift string and get a double back (example output comes first)这是一个扩展方法,它允许您简单地在 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

Here's the extension method:这是扩展方法:

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
    }
}

No error checking, but you can add it if you need it.没有错误检查,但您可以根据需要添加它。

As of Swift 1.1, you can directly pass String to const char * parameter.从 Swift 1.1 开始,您可以直接将String传递给const char *参数。

import Foundation

let str = "123.4567"
let num = atof(str) // -> 123.4567

atof("123.4567fubar") // -> 123.4567

If you don't like deprecated atof :如果您不喜欢已弃用的atof

strtod("765.4321", nil) // -> 765.4321

One caveat: the behavior of conversion is different from NSString.doubleValue .一个警告:转换的行为不同于NSString.doubleValue

atof and strtod accept 0x prefixed hex string: atofstrtod接受0x前缀的十六进制字符串:

atof("0xffp-2") // -> 63.75
atof("12.3456e+2") // -> 1,234.56
atof("nan") // -> (not a number)
atof("inf") // -> (+infinity)

If you prefer .doubleValue behavior, we can still use CFString bridging:如果您更喜欢.doubleValue行为,我们仍然可以使用CFString桥接:

let str = "0xff"
atof(str)                      // -> 255.0
strtod(str, nil)               // -> 255.0
CFStringGetDoubleValue(str)    // -> 0.0
(str as NSString).doubleValue  // -> 0.0

I haven't seen the answer I was looking for.我还没有看到我正在寻找的答案。 I just post in here mine in case it can help anyone.我只是在这里发布我的,以防它可以帮助任何人。 This answer is valid only if you don't need a specific format .仅当您不需要特定格式时,此答案有效。

Swift 3斯威夫特 3

extension String {
    var toDouble: Double {
        return Double(self) ?? 0.0
    }
}

In Swift 2.0 the best way is to avoid thinking like an Objective-C developer.在 Swift 2.0 中,最好的方法是避免像 Objective-C 开发人员那样思考。 So you should not "convert a String to a Double" but you should "initialize a Double from a String".所以你不应该“将字符串转换为双精度”,而应该“从字符串初始化双精度”。 Apple doc over here: https://developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Double_Structure/index.html#//apple_ref/swift/structctr/Double/s:FSdcFMSdFSSGSqSd_苹果文档在这里: https : //developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Double_Structure/index.html#//apple_ref/swift/structctr/Double/s : FSdcFMSdFSSGSqSd_

It's an optional init so you can use the nil coalescing operator (??) to set a default value.它是一个可选的 init,因此您可以使用 nil 合并运算符 (??) 来设置默认值。 Example:例子:

let myDouble = Double("1.1") ?? 0.0

On SWIFT 3 , you can use:SWIFT 3 上,您可以使用:

if let myDouble = NumberFormatter().number(from: yourString)?.doubleValue {
   print("My double: \(myDouble)")
}

Note: - If a string contains any characters other than numerical digits or locale-appropriate group or decimal separators, parsing will fail.注意: - 如果字符串包含除数字或区域设置适当的组或小数分隔符以外的任何字符,解析将失败。 - Any leading or trailing space separator characters in a string are ignored. - 字符串中的任何前导或尾随空格分隔符都将被忽略。 For example, the strings “ 5”, “5 ”, and “5” all produce the number 5.例如,字符串“5”、“5”和“5”都产生数字 5。

Taken from the documentation: https://developer.apple.com/reference/foundation/numberformatter/1408845-number取自文档: https : //developer.apple.com/reference/foundation/numberformatter/1408845-number

Try this:尝试这个:

   var myDouble = myString.bridgeToObjectiveC().doubleValue
   println(myDouble)

NOTE笔记

Removed in Beta 5. This no longer works ?在 Beta 5 中删除。这不再有效?

This is building upon the answer by @Ryu这是建立在@Ryu 的回答之上的

His solution is great as long as you're in a country where dots are used as separators.只要您在使用点作为分隔符的国家/地区,他的解决方案就很棒。 By default NSNumberFormatter uses the devices locale.默认情况下NSNumberFormatter使用设备区域设置。 Therefore this will fail in all countries where a comma is used as the default separator (including France as @PeterK. mentioned) if the number uses dots as separators (which is normally the case).因此,如果数字使用点作为分隔符(通常是这种情况),那么这将在所有使用逗号作为默认分隔符的国家/地区失败(包括法国作为@PeterK。提到)。 To set the locale of this NSNumberFormatter to be US and thus use dots as separators replace the line将此 NSNumberFormatter 的语言环境设置为 US 并因此使用点作为分隔符替换该行

return NSNumberFormatter().numberFromString(self)?.doubleValue

with

let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue

Therefore the full code becomes因此完整的代码变成

extension String {
    func toDouble() -> Double? {
        let numberFormatter = NSNumberFormatter()
        numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
        return numberFormatter.numberFromString(self)?.doubleValue
    }
}

To use this, just call "Your text goes here".toDouble()要使用它,只需调用"Your text goes here".toDouble()

This will return an optional Double?这将返回一个可选的Double?

As @Ryu mentioned you can either force unwrap:正如@Ryu 提到的,您可以强制解包:

println("The value is \(myDouble!)") // prints: The value is 4.2

or use an if let statement:或使用if let语句:

if let myDouble = myDouble {
    println("The value is \(myDouble)") // prints: The value is 4.2
}

SWIFT 4快速 4

extension String {
    func toDouble() -> Double? {
        let numberFormatter = NumberFormatter()
        numberFormatter.locale = Locale(identifier: "en_US_POSIX")
        return numberFormatter.number(from: self)?.doubleValue
    }
}

Swift 4.0斯威夫特 4.0

try this尝试这个

 let str:String = "111.11"
 let tempString = (str as NSString).doubleValue
 print("String:-",tempString)

Swift : 4 and 5斯威夫特:4 和 5

There are possibly two ways to do this:可能有两种方法可以做到这一点:

  1. String -> Int -> Double:字符串 -> 整数 -> 双精度:

     let strNumber = "314" if let intFromString = Int(strNumber){ let dobleFromInt = Double(intFromString) print(dobleFromInt) }
  2. String -> NSString -> Double字符串 -> NSString -> 双精度

    let strNumber1 = "314" let NSstringFromString = NSString(string: strNumber1) let doubleFromNSString = NSstringFromString.doubleValue print(doubleFromNSString)

Use it anyway you like according to you need of the code.根据您对代码的需要,随意使用它。

Please check it on playground!请在操场上检查!

let sString = "236.86"

var dNumber = NSNumberFormatter().numberFromString(sString)
var nDouble = dNumber!
var eNumber = Double(nDouble) * 3.7

By the way in my Xcode顺便说一句,在我的 Xcode 中

.toDouble() - doesn't exist .toDouble() - 不存在

.doubleValue create value 0.0 from not numerical strings... .doubleValue 从非数字字符串创建值 0.0...

As already pointed out, the best way to achieve this is with direct casting:正如已经指出的那样,实现这一目标的最佳方法是直接铸造:

(myString as NSString).doubleValue

Building from that, you can make a slick native Swift String extension:以此为基础,你可以制作一个漂亮的原生 Swift String 扩展:

extension String {
    var doubleValue: Double {
        return (self as NSString).doubleValue
    }
}

This allows you to directly use:这允许您直接使用:

myString.doubleValue

Which will perform the casting for you.哪个将为您执行铸造。 If Apple does add a doubleValue to the native String you just need to remove the extension and the rest of your code will automatically compile fine!如果 Apple 确实向本机 String 添加了doubleValue ,您只需要删除扩展名,其余代码将自动编译正常!

1. 1.

let strswift = "12"
let double = (strswift as NSString).doubleValue

2. 2.

var strswift= "10.6"
var double : Double = NSString(string: strswift).doubleValue 

May be this help for you.可能对你有帮助。

SWIFT 3斯威夫特 3

To clear, nowadays there is a default method:要清除,现在有一个默认方法:

public init?(_ text: String)` of `Double` class.

It can be used for all classes.它可以用于所有类。

let c = Double("-1.0")
let f = Double("0x1c.6")
let i = Double("inf")

, etc. , 等等。

Extension with optional locale带有可选语言环境的扩展

Swift 2.2斯威夫特 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
    }
}

Swift 3.1斯威夫特 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
        }
    }
}

或者你可以这样做:

var myDouble = Double((mySwiftString.text as NSString).doubleValue)

You can use StringEx .您可以使用StringEx It extends String with string-to-number conversions including toDouble() .它使用字符串到数字的转换来扩展String ,包括toDouble()

extension String {
    func toDouble() -> Double?
}

It verifies the string and fails if it can't be converted to double.它验证字符串,如果不能转换为双精度则失败。

Example:例子:

import StringEx

let str = "123.45678"
if let num = str.toDouble() {
    println("Number: \(num)")
} else {
    println("Invalid string")
}

Swift 4斯威夫特 4

extension String {
    func toDouble() -> Double {
        let nsString = self as NSString
        return nsString.doubleValue
    }
}

What also works:什么也有效:

// 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.

Use this code in Swift 2.0在 Swift 2.0 中使用此代码

let strWithFloat = "78.65"
let floatFromString = Double(strWithFloat)

Using Scanner in some cases is a very convenient way of extracting numbers from a string.在某些情况下,使用Scanner是从字符串中提取数字的一种非常方便的方法。 And it is almost as powerful as NumberFormatter when it comes to decoding and dealing with different number formats and locales.在解码和处理不同的数字格式和语言环境时,它几乎与NumberFormatter一样强大。 It can extract numbers and currencies with different decimal and group separators.它可以提取具有不同小数和组分隔符的数字和货币。

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)
        }

    }
}

However, there are issues with separators that could be conceived as word delimiters.但是,可以将分隔符视为单词分隔符存在一些问题。

// 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

There is no problem to auto detect locale.自动检测语言环境没有问题。 Note that groupingSeparator in French locale in string "Mon salaire est 9 999,99€" is not a space, though it may render exactly as space (here it doesn't).请注意,字符串 "Mon salaire est 9 999,99€" 中法语语言环境中的 groupingSeparator 不是空格,尽管它可能完全呈现为空格(这里不是)。 Thats why the code below works fine without !$0.isWhitespace characters being filtered out.这就是为什么下面的代码没有过滤掉!$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)

In the cases of strings contain other characters like: "27.8 °C" , "52.523553 kM" or "Total: 349.0" .如果字符串包含其他字符,例如: "27.8 °C""52.523553 kM""Total: 349.0"

This works in Swift 4:这适用于 Swift 4:

let anyString = "52.523553 kM"
let digitsCharacterSet = CharacterSet.init(charactersIn: "0123456789.")
let doubleResult = Double(anyString.components(separatedBy:digitsCharacterSet.inverted).joined())

Caution!警告! This not working for strings contain multiple .这不适用于包含多个. like "27.8 °C 3.5 kM""27.8 °C 3.5 kM"

I find more readable to add an extension to String as follow:我发现将扩展添加到 String 更具可读性,如下所示:

extension String {
    var doubleValue: Double {
        return (self as NSString).doubleValue
    }
}

and then you just could write your code:然后你就可以写你的代码:

myDouble = myString.doubleValue

my problem was comma so i solve it this way:我的问题是逗号,所以我这样解决:

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 值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM