Я пытаюсь написать программу BMI на быстром языке. И у меня возникла проблема: как преобразовать строку в двойную?
В Objective-C я могу сделать так:
double myDouble = [myString doubleValue];
Но как мне добиться этого на языке Swift?
Я пытаюсь написать программу BMI на быстром языке. И у меня возникла проблема: как преобразовать строку в двойную?
В Objective-C я могу сделать так:
double myDouble = [myString doubleValue];
Но как мне добиться этого на языке Swift?
Ответы:
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 (и валюту) .
Обновление Swift 2
Появились новые неисправные инициализаторы, которые позволяют вам делать это более идиоматичным и безопасным способом (как отмечалось во многих ответах, двойное значение NSString не очень безопасно, поскольку оно возвращает 0 для нечисловых значений. Это означает, что doubleValueof "foo"и "0"являются тот же самый.)
let myDouble = Double(myString)
Это возвращает необязательный параметр, поэтому в случаях, когда передается, "foo"где doubleValueбы возвратил 0, возвращается неисправный инициализатор nil. Вы можете использовать guard, if-letили mapдля обрабатыватьOptional<Double>
Исходное сообщение: Вам не нужно использовать конструктор NSString, как предлагает принятый ответ. Вы можете просто соединить это так:
(swiftString as NSString).doubleValue
- [NSString doubleValue]является Doubleбыстрым по сравнению с Double?( Optional<Double>). Это отличается от функции Swift String, toInt()которая возвращает Int?и указывает в документах, что она "... принимает строки, соответствующие регулярному выражению" [- +]? [0-9] + "only". "
.toInt()будет лучше. Однако это был скорее ответ на вопрос, как сделать то же самое, но в Swift.
Double.init?(_ text: String)теперь доступен сбойный инициализатор.
Для немного большего ощущения Swift, использование NSFormatter()избегает приведения NSStringи возвращает, nilкогда строка не содержит Doubleзначения (например, «test» не вернется 0.0).
let double = NSNumberFormatter().numberFromString(myString)?.doubleValue
В качестве альтернативы, расширение Stringтипа Swift :
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
Вот метод расширения, который позволяет вам просто вызвать 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
}
}
Нет проверки ошибок, но вы можете добавить его, если вам это нужно.
Начиная с 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. Таким образом, вы не должны «преобразовывать строку в двойную», но вы должны «инициализировать двойную строку». 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, а потому, что этот инициализатор не был доступен ранее.
На 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)
НОТА
Удалено в бета-версии 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
попробуй это
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)
let 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 из нечисловых строк ...
1.
let strswift = "12"
let double = (strswift as NSString).doubleValue
2.
var strswift= "10.6"
var double : Double = NSString(string: strswift).doubleValue
Может быть, это поможет вам.
Как уже указывалось, лучший способ добиться этого с помощью прямого литья:
(myString as NSString).doubleValue
Основываясь на этом, вы можете сделать отличное расширение Swift String:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
Это позволяет напрямую использовать:
myString.doubleValue
Который будет выполнять кастинг для вас. Если Apple добавит doubleValueстроку к нативной строке, вам просто нужно удалить расширение, а остальная часть вашего кода будет автоматически скомпилирована!
Расширение с дополнительным языковым стандартом
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
}
}
}
Вы можете использовать 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")
}
Swift 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.
Используйте этот код в Swift 2.0
let strWithFloat = "78.65"
let floatFromString = Double(strWithFloat)
Использование 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
Нет проблем с автоматическим определением локали. Обратите внимание, что groupingSeparator во французском языке в строке «Mon salaire est 9 999,99 €» не является пробелом, хотя может отображаться точно как пробел (здесь это не так). Вот почему приведенный ниже код прекрасно работает без !$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)
моя проблема была запятая, поэтому я решаю ее так:
extension String {
var doubleValue: Double {
return Double((self.replacingOccurrences(of: ",", with: ".") as NSString).doubleValue)
}
}
var stringValue = "55"
var convertToDouble = Double((stringValue as NSString).doubleValue)
мы можем использовать значение CDouble, которое будет получено myString.doubleValue