ฉันกำลังพยายามเขียนโปรแกรม BMI ในภาษาที่รวดเร็ว และฉันได้รับปัญหานี้: จะแปลงสตริงเป็นคู่ได้อย่างไร
ใน Objective-C ฉันสามารถทำสิ่งนี้ได้:
double myDouble = [myString doubleValue];
แต่ฉันจะทำสิ่งนี้ในภาษาสวิฟต์ได้อย่างไร
ฉันกำลังพยายามเขียนโปรแกรม BMI ในภาษาที่รวดเร็ว และฉันได้รับปัญหานี้: จะแปลงสตริงเป็นคู่ได้อย่างไร
ใน Objective-C ฉันสามารถทำสิ่งนี้ได้:
double myDouble = [myString doubleValue];
แต่ฉันจะทำสิ่งนี้ในภาษาสวิฟต์ได้อย่างไร
คำตอบ:
Swift 4.2+ String เป็น Double
คุณควรใช้ initializers ชนิดใหม่เพื่อแปลงระหว่างชนิดสตริงและตัวเลข (Double, Float, Int) มันจะกลับมาเป็นตัวเลือกประเภท (สองครั้ง?) ซึ่งจะมีค่าที่ถูกต้องหรือไม่มีถ้าสตริงไม่ได้เป็นตัวเลข
หมายเหตุ:ไม่แนะนำให้ใช้คุณสมบัติ 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 ประเภทคู่ (และเงิน)
สวิฟท์ 2 ปรับปรุง
มี initializers failable ใหม่ที่ช่วยให้คุณสามารถทำเช่นนี้ในทางสำนวนและมีความปลอดภัยมากขึ้น (เป็นคำตอบที่หลายคนได้ตั้งข้อสังเกตค่า double NSString ไม่ได้ปลอดภัยมากเพราะมันกลับ 0 สำหรับค่าตัวเลขที่ไม่ใช่ว่ามี. ซึ่งหมายความว่าdoubleValue
ของ"foo"
และ"0"
มี เหมือน.)
let myDouble = Double(myString)
นี้จะส่งกลับตัวดังนั้นในกรณีเช่นผ่านใน"foo"
ที่doubleValue
จะได้กลับ 0 intializer failable nil
จะกลับมา คุณสามารถใช้guard
, if-let
หรือmap
ในการจัดการOptional<Double>
โพสต์ต้นฉบับ: คุณไม่จำเป็นต้องใช้ตัวสร้าง NSString เหมือนคำตอบที่ยอมรับ คุณสามารถบริดจ์มันได้อย่างนี้:
(swiftString as NSString).doubleValue
- [NSString doubleValue]
เป็นDouble
ในรวดเร็ว apposed เป็นไปDouble?
( Optional<Double>
) สิ่งนี้แตกต่างจากฟังก์ชั่น Swift String toInt()
ที่ส่งคืนInt?
และระบุในเอกสารว่า "... ยอมรับสตริงที่ตรงกับนิพจน์ทั่วไป" [- +]? [0-9] + "เท่านั้น
.toInt()
จะดีกว่า อย่างไรก็ตามนี่เป็นคำตอบเพิ่มเติมเกี่ยวกับวิธีการทำสิ่งเดียวกัน แต่ใน Swift
Double.init?(_ text: String)
ตอนนี้มี initializer พร้อมใช้งาน
สำหรับความรู้สึกที่รวดเร็วกว่าเล็กน้อยให้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 และรับ double backback (ตัวอย่างเอาต์พุตมาก่อน)
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
}
}
ไม่มีการตรวจสอบข้อผิดพลาด แต่คุณสามารถเพิ่มได้หากคุณต้องการ
ในฐานะของสวิฟท์ 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:FSdcFMSdFSSFSqFSDFS
เป็นตัวเลือก init เพื่อให้คุณสามารถใช้ตัวดำเนินการรวมศูนย์ (??) เพื่อตั้งค่าเริ่มต้น ตัวอย่าง:
let myDouble = Double("1.1") ?? 0.0
Double.init?(_ text: String)
มีให้ใน Swift 2.0 คุณควรพูดถึงสิ่งนี้ คำตอบอื่น ๆ ที่นี่ไม่ใช่เพราะคนคิดว่าเป็นนักพัฒนา Objective-C แต่เป็นเพราะ initializer นี้ไม่สามารถใช้ได้ก่อนหน้านี้
บน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
ฉันไม่เห็นคำตอบที่ต้องการ ฉันเพิ่งโพสต์ที่นี่ของฉันในกรณีที่สามารถช่วยให้ทุกคน คำตอบนี้สามารถใช้ได้เฉพาะในกรณีที่คุณไม่จำเป็นต้องรูปแบบที่เฉพาะเจาะจง
สวิฟท์ 3
extension String {
var toDouble: Double {
return Double(self) ?? 0.0
}
}
ลองสิ่งนี้:
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
SWIFT 4
extension String {
func toDouble() -> Double? {
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "en_US_POSIX")
return numberFormatter.number(from: self)?.doubleValue
}
}
ลองนี้
let str:String = "111.11"
let tempString = (str as NSString).doubleValue
print("String:-",tempString)
Swift: 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 เพิ่ม a doubleValue
ให้กับสายอักขระดั้งเดิมคุณเพียงแค่ลบส่วนขยายออกและส่วนที่เหลือของรหัสของคุณจะทำการรวบรวมโดยอัตโนมัติ!
สวิฟท์ 3
เพื่อล้างทุกวันนี้มีวิธีการเริ่มต้น:
public init?(_ text: String)
ของDouble
ชั้นเรียน
มันสามารถใช้สำหรับทุกชั้น
let c = Double("-1.0")
let f = Double("0x1c.6")
let i = Double("inf")
ฯลฯ
ส่วนขยายพร้อมด้วยโลแคลเผื่อเลือก
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
}
}
สวิฟท์ 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)
คุณสามารถใช้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.
ใช้รหัสนี้ใน 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
ไม่มีปัญหาในการตรวจหาสถานที่อัตโนมัติ โปรดทราบว่าการจัดกลุ่มตัวแยกในภาษาฝรั่งเศสในสตริง "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)
ฉันค้นหาเพิ่มเติมเพื่อเพิ่มส่วนขยายใน 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)
เราสามารถใช้ค่า CDouble ซึ่งจะได้รับจาก myString.doubleValue