Swift - Как конвертировать String в Double

191

Я пытаюсь написать программу BMI на быстром языке. И у меня возникла эта проблема: как преобразовать строку в двойную?

В Objective-C я могу сделать вот так:

double myDouble = [myString doubleValue];

Но как я могу добиться этого на языке Swift?

  • 1
    Это изменилось в Swift 2, см. Новый ответ, используя новый сбойный инициализатор Double (): stackoverflow.com/a/32850058/276626
Теги:
swift-converter

28 ответов

93
Лучший ответ

Swift 4. 2+ Строка для удвоения

Вы должны использовать инициализаторы нового типа для преобразования между строковым и числовым типами (Double, Float, Int). Он вернет необязательный тип (Double?), Который будет иметь правильное значение или ноль, если строка не была числом.

Примечание. Свойство 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")

Читайте больше в моем блоге о преобразовании типа String в Double (и валюту).

  • 1
    это должно стать самым высоко оцененным ответом. (Я собирался добавить его сам, но проверил, сделал ли это кто-нибудь еще)
  • 2
    Другая проблема заключается в том, что он не поддерживает числа в других языковых стандартах, кроме 1000,00. Если вы используете другие форматы, например 1 000,00, в конце будет обрезано 2 знака после запятой. По крайней мере, это то, что происходит с Objective-C. - В соответствии с документацией Apple: (они не учитывают языковой стандарт). Все следующие удобные методы пропускают начальные пробелы (whitespaceSet) и игнорируют завершающие символы. Они не осведомлены о локали. NSScanner или NSNumberFormatter могут использоваться для более мощного и ориентированного на локали анализа чисел.
Показать ещё 2 комментария
273

Обновление Swift 2 Существуют новые отказоустойчивые инициализаторы, которые позволяют вам делать это более идиоматичным и безопасным способом (как было отмечено многими ответами, двойное значение NSString не очень безопасно, потому что оно возвращает 0 для значений без номера. Это означает, что doubleValue of "foo" и "0" совпадают.)

let myDouble = Double(myString)

Возвращает необязательный параметр, поэтому в случаях, когда передача "foo", где doubleValue вернула бы 0, возвращаемый intializer вернет nil. Вы можете использовать guard, if-let или map для обработки Optional<Double>

Оригинальное сообщение: Вам не нужно использовать конструктор NSString, как предлагает принятый ответ. Вы можете просто провести его так:

(swiftString as NSString).doubleValue
  • 1
    работает отлично! и мне нравится более лаконичная форма.
  • 0
    Yeap! Это работает, и это также самый короткий! Спасибо!
Показать ещё 9 комментариев
71

Для немного более быстрого ощущения, используя NSFormatter(), избегает кастинга до NSString и возвращает nil, когда строка не содержит значения Double (например, "test" не вернет 0.0).

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

В качестве альтернативы, расширение типа Swift String:

extension String {
    func toDouble() -> Double? {
        return NSNumberFormatter().numberFromString(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
}

Update: Для локализации очень легко применять локали к NSFormatter следующим образом:

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

Наконец, вы можете использовать NSNumberFormatterCurrencyStyle в форматировании, если работаете с валютами, где строка содержит символ валюты.

  • 0
    Мне нравится идея расширения класса String для приложений, которые будут использовать конвертацию в нескольких местах. Но я не вижу выгоды от сложности вызова NSNumberFormatter, поскольку приведение к NSString и использование .doubleValue, по-видимому, по крайней мере так же прямое, и их легче читать и запоминать.
  • 12
    На самом деле преимущество использования NSNumberFormatter () состоит в том, что numberFromString: метод вернет nil, если строка содержит символы, которые не составляют двойное число. Проблема с doubleValue на NSString заключается в том, что он всегда будет возвращать double (например, 0.0 для «test») независимо. Поэтому, если вы имеете дело со всеми видами строк и хотите проверить, является ли строка просто двойной, без дополнительных символов, используйте NSNumberFormatter.
Показать ещё 3 комментария
52

Другим вариантом здесь является преобразование этого в NSString и использование этого:

let string = NSString(string: mySwiftString)
string.doubleValue
  • 13
    Я бы хотел, чтобы был лучший способ сделать это. Как я могу узнать, если разбор не удался, например.
  • 2
    @RyanHoffman К сожалению, в контракте NSString doubleValue этого никогда не было. Все, что вы получите, это 0.0, если строка не начинается с правильного представления числа, HUGE_VAL и -HUGE_VAL при переполнении / потоке. Если вы хотите знать, почему не удалось выполнить синтаксический анализ, я считаю, что вам нужно взглянуть на NSNumberFormatter, который был разработан для более надежной обработки преобразования чисел и строк.
Показать ещё 4 комментария
24

Здесь используется метод расширения, который позволяет вам просто вызвать doubleValue() в строке Swift и получить двойную обратную сторону (сначала выводится вывод)

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

Нет проверки ошибок, но вы можете добавить его, если вам это нужно.

  • 2
    Это определенно лучший из вариантов. Если вы читаете «Быструю книгу», дополнения приветствуются ... Это был последний вариант, о котором я тоже подумал! : D Я делаю все возможное, чтобы избежать мостов, так что слава за это!
18

С 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
  • 0
    Я фанат этого подхода вместо того, чтобы использовать NSString .
  • 0
    Красиво и лаконично, мне это нравится.
10

В Swift 2.0 лучший способ - не думать о разработчике Objective-C. Таким образом, вы не должны "преобразовывать строку в двойную", но вам следует "инициализировать Double from the String". Apple doc здесь: 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
  • 0
    Double.init?(_ text: String) становятся доступными в Swift 2.0. Вы должны упомянуть об этом. Другие ответы здесь не потому, что люди думают как разработчики Objective-C, а потому, что этот инициализатор не был доступен ранее.
  • 0
    Действительно, ты прав. Это доступно только в Swift 2.0, я упомяну об этом :) Но, как и в других языках, вы инициализируете тип с другим и не должны ожидать, что тип сможет конвертировать в другой. Долгие дебаты, но, как разработчик Obj-C, у меня много плохих практик при программировании со Swift, и это одна из них :)
Показать ещё 1 комментарий
9

В 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

9

Попробуйте следующее:

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

Примечание

Удалено в бета-версии 5. Это больше не работает?

  • 1
    bridgeToObjectiveC () был удален в Xcode 6 Beta 5. Метод мистера Смайли - самый быстрый, который я нашел на данный момент
6

Я не видел ответа, который я искал. Я просто размещаю здесь свой, если он может помочь кому угодно. Этот ответ действителен только в том случае, если вам не нужен конкретный формат.

Swift 3

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

Это основано на ответе @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
}
  • 1
    Это правильный ответ. Версия Swift 3 будет NumberFormatter().number(from: myString)?.doubleValue
5

SWIFT 4

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

SWIFT 3

Чтобы очистить, в настоящее время существует метод по умолчанию:

public init?(_ text: String) класса Double.

Он может использоваться для всех классов.

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

4

Пожалуйста, проверьте это на детской площадке!

let sString = "236.86"

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

Кстати, в моем Xcode

.toDouble() - не существует

.doubleValue создает значение 0.0 из не числовых строк...

3

Swift 4.0

попробуй это

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

Расширение с дополнительным языковым стандартом

Swift 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

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
        }
    }
}
  • 0
    Пожалуйста, обновите до Swift 3 и добавьте пример для локали. Спасибо.
  • 0
    Это всегда хорошо, чтобы привести пример использования. Спасибо.
3

Как уже указывалось, лучший способ достичь этого - с прямым литьем:

(myString as NSString).doubleValue

Создавая это, вы можете сделать плавное расширение Swift String:

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

Это позволяет вам напрямую использовать:

myString.doubleValue

Который выполнит кастинг для вас. Если Apple добавит doubleValue к родной String, вам просто нужно удалить расширение, а остальная часть вашего кода будет автоматически компилироваться.

  • 0
    Метод Apple будет называться .toDouble ... так же, как toInt. Это странное упущение. Вероятно, будет исправлено в будущей версии Swift. Мне больше нравится метод расширения, он сохраняет код в чистоте.
  • 0
    Возвращаемое значение должно быть Double NOT a Float
3

1.

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

2.

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

Может быть, эта помощь для вас.

1

Swift 4

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

Свифт: - 4

Есть два способа сделать это:

  1. String → Int → Double:

    let strNumber = "314"
    let intFromString = Int(strNumber)
    let dobleFromInt = Double(intFromString!)
    print(dobleFromInt)
    
  2. String → NSString → Double

    let strNumber = "314"
    let NSstringFromString = NSString(string: strNumber as! NSString)
    let doubleFromNSString = NSstringFromString.doubleValue
    print(doubleFromNSString)
    

Используйте его так, как вам нравится, в соответствии с вашими требованиями.

1

Вы можете использовать StringEx. Он расширяет String с преобразованием строк в число, включая toDouble().

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

Он проверяет строку и терпит неудачу, если ее нельзя преобразовать в double.

Пример:

import StringEx

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

Или вы могли бы сделать:

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

Используйте этот код в Swift 2.0

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

0

Что также работает:

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

Я нахожу более читаемым, чтобы добавить расширение к String следующим образом:

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

а затем вы можете написать свой код:

myDouble = myString.doubleValue
-1

Моя проблема была запятой, поэтому я решаю ее следующим образом:

extension String {
    var doubleValue: Double {
        return Double((self.replacingOccurrences(of: ",", with: ".") as NSString).doubleValue)
    }
}
-2
var stringValue = "55"

var convertToDouble = Double((stringValue as NSString).doubleValue)
-7

мы можем использовать значение CDouble, которое будет получено myString.doubleValue

  • 0
    Ошибка: у «String» нет члена с именем «doubleValue»
  • 0
    @ Matthew Да, нет члена с двойным значением, поэтому мы можем использовать CDouble Value
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню