การจัดรูปแบบอินพุตสำหรับสกุลเงินด้วย NSNumberFormatter ใน Swift

ฉันกำลังสร้างแอปงบประมาณที่ให้ผู้ใช้สามารถป้อนงบประมาณและธุรกรรมได้ ฉันต้องอนุญาตให้ผู้ใช้ป้อนทั้งเพนนีและปอนด์จากช่องข้อความแยกกัน และต้องจัดรูปแบบพร้อมกับสัญลักษณ์สกุลเงิน ฉันใช้งานได้ดีในขณะนี้ แต่ต้องการทำให้เป็นภาษาท้องถิ่น เนื่องจากขณะนี้ใช้งานได้กับ GBP เท่านั้น ฉันพยายามแปลงตัวอย่าง NSNumberFormatter จาก Objective-C เป็น Swift

ปัญหาแรกของฉันคือฉันต้องตั้งค่าตัวยึดตำแหน่งสำหรับช่องป้อนข้อมูลให้เฉพาะเจาะจงกับตำแหน่งของผู้ใช้ เช่น. ปอนด์และเพนนี ดอลลาร์และเซนต์ ฯลฯ ...

ปัญหาที่สองคือค่าที่ป้อนในแต่ละฟิลด์ข้อความ เช่น 10216 และ 32 จำเป็นต้องได้รับการจัดรูปแบบ และจำเป็นต้องเพิ่มสัญลักษณ์สกุลเงินเฉพาะสำหรับตำแหน่งที่ตั้งของผู้ใช้ ดังนั้นมันจะกลายเป็น 10,216.32 ปอนด์หรือ 10,216.32 ดอลลาร์ ฯลฯ...

นอกจากนี้ ฉันยังต้องใช้ผลลัพธ์ของตัวเลขที่จัดรูปแบบในการคำนวณอีกด้วย ดังนั้นฉันจะทำอย่างไรโดยที่ไม่มีปัญหากับสัญลักษณ์สกุลเงิน?


person user3746428    schedule 25.07.2014    source แหล่งที่มา
comment
คุณสามารถโพสต์ตัวอย่างของรหัสที่ไม่ทำงานได้ไหม?   -  person NiñoScript    schedule 25.07.2014


คำตอบ (10)


นี่คือตัวอย่างวิธีใช้งานบน Swift 3 ( แก้ไข: ใช้งานได้ใน Swift 5 ด้วย)

let price = 123.436 as NSNumber

let formatter = NumberFormatter()
formatter.numberStyle = .currency
// formatter.locale = NSLocale.currentLocale() // This is the default
// In Swift 4, this ^ was renamed to simply NSLocale.current
formatter.string(from: price) // "$123.44"

formatter.locale = Locale(identifier: "es_CL")
formatter.string(from: price) // $123"

formatter.locale = Locale(identifier: "es_ES")
formatter.string(from: price) // "123,44 €"

นี่คือตัวอย่างเก่าเกี่ยวกับวิธีใช้งานบน Swift 2

let price = 123.436

let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
// formatter.locale = NSLocale.currentLocale() // This is the default
formatter.stringFromNumber(price) // "$123.44"

formatter.locale = NSLocale(localeIdentifier: "es_CL")
formatter.stringFromNumber(price) // $123"

formatter.locale = NSLocale(localeIdentifier: "es_ES")
formatter.stringFromNumber(price) // "123,44 €"
person NiñoScript    schedule 25.07.2014
comment
ขอบคุณ. ฉันได้แก้ไขคำถามของฉันและเจาะจงมากขึ้น - person user3746428; 25.07.2014
comment
จากตัวอย่างที่คุณให้มา ฉันสามารถนำการจัดรูปแบบตัวเลขไปใช้กับโปรแกรมของฉันได้ ดังนั้นบิตนั้นจึงถูกจัดเรียง ตอนนี้ฉันแค่ต้องหาวิธีตั้งค่าตัวยึดช่องข้อความตามตำแหน่งของผู้ใช้ - person user3746428; 25.07.2014
comment
ไม่จำเป็นต้องส่งไปที่ NSNumber คุณสามารถใช้เมธอดฟอร์แมตเตอร์ func string (สำหรับ obj: Any?) -› String? ดังนั้นคุณเพียงแค่ต้องใช้ string(for: price) แทน string(from: price) - person Leo Dabus; 22.03.2017
comment
@LeoDabus คุณพูดถูก ฉันไม่รู้เกี่ยวกับวิธีการนั้น ฉันไม่แน่ใจว่าควรแก้ไขคำตอบของฉันหรือไม่ เพราะฉันคิดว่าฉันควรใช้ API ของ NumberFormatter และชัดเจนเกี่ยวกับการใช้ NSNumber แทนที่จะปล่อยให้มันโดยปริยาย โยนมันเข้าไปข้างใน - person NiñoScript; 22.03.2017
comment
โปรดทราบว่าผลลัพธ์ของ formatter.string(from:) เป็นสตริงทางเลือก ไม่ใช่สตริง (ตามนัยของความคิดเห็น) ดังนั้นจะต้องแกะก่อนใช้งาน - person Ali Beadle; 10.09.2017
comment
การส่งคืนสตริงทางเลือกเป็นส่วนสำคัญของการแปลงเป็น NSNumber ในที่นี้ในพื้นที่ที่รวดเร็ว เรารู้ว่าเป็นตัวเลขจริงและจะไม่มีวันล้มเหลว ดังนั้นเราจึงสามารถบังคับแกะมันออกได้ - person NiñoScript; 25.09.2018

สวิฟท์ 3:

หากคุณกำลังมองหาโซลูชั่นที่ช่วยให้คุณ:

  • "5" = "$5"
  • "5.0" = "$5"
  • "5.00" = "$5"
  • "5.5" = "$5.50"
  • "5.50" = "$5.50"
  • "5.55" = "$5.55"
  • "5.234234" = "5.23"

กรุณาใช้สิ่งต่อไปนี้:

func cleanDollars(_ value: String?) -> String {
    guard value != nil else { return "$0.00" }
    let doubleValue = Double(value!) ?? 0.0
    let formatter = NumberFormatter()
    formatter.currencyCode = "USD"
    formatter.currencySymbol = "$"
    formatter.minimumFractionDigits = (value!.contains(".00")) ? 0 : 2
    formatter.maximumFractionDigits = 2
    formatter.numberStyle = .currencyAccounting
    return formatter.string(from: NSNumber(value: doubleValue)) ?? "$\(doubleValue)"
}
person Gregg    schedule 08.12.2016
comment
ไม่จำเป็นต้องเริ่มต้นวัตถุ NSNumber ใหม่ คุณสามารถใช้วิธีฟอร์แมตเตอร์ func string(for obj: Any?) -> String? แทน string(from:) - person Leo Dabus; 22.03.2017

ฉันได้ใช้โซลูชันที่ได้รับจาก @NiñoScript เป็นส่วนขยายเช่นกัน:

ส่วนขยาย

// Create a string with currency formatting based on the device locale
//
extension Float {
    var asLocaleCurrency:String {
        var formatter = NSNumberFormatter()
        formatter.numberStyle = .CurrencyStyle
        formatter.locale = NSLocale.currentLocale()
        return formatter.stringFromNumber(self)!
    }
}

การใช้งาน:

let amount = 100.07
let amountString = amount.asLocaleCurrency
print(amount.asLocaleCurrency())
// prints: "$100.07"

สวิฟท์ 3

    extension Float {
    var asLocaleCurrency:String {
        var formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = Locale.current
        return formatter.string(from: self)!
    }
}
person Michael Voccola    schedule 24.04.2015
comment
ส่วนขยายควรขยาย FloatingPoint สำหรับเวอร์ชัน Swift 3 และสตริง (จาก: วิธีการสำหรับ NSNumber สำหรับประเภท FlotingPoint คุณต้องใช้วิธี string (สำหรับ :) ฉันได้โพสต์ส่วนขยาย Swift 3 แล้ว - person Leo Dabus; 22.03.2017
comment
อย่าใช้ประเภทลอยตัวสำหรับสกุลเงิน ให้ใช้ทศนิยม - person adnako; 14.03.2018

Xcode 11 • Swift 5.1

extension Locale {
    static let br = Locale(identifier: "pt_BR")
    static let us = Locale(identifier: "en_US")
    static let uk = Locale(identifier: "en_GB") // ISO Locale
}

extension NumberFormatter {
    convenience init(style: Style, locale: Locale = .current) {
        self.init()
        self.locale = locale
        numberStyle = style
    }
}

extension Formatter {
    static let currency = NumberFormatter(style: .currency)
    static let currencyUS = NumberFormatter(style: .currency, locale: .us)
    static let currencyBR = NumberFormatter(style: .currency, locale: .br)
}

extension Numeric {
    var currency: String { Formatter.currency.string(for: self) ?? "" }
    var currencyUS: String { Formatter.currencyUS.string(for: self) ?? "" }
    var currencyBR: String { Formatter.currencyBR.string(for: self) ?? "" }
}

let price = 1.99

print(Formatter.currency.locale)  // "en_US (current)\n"
print(price.currency)             // "$1.99\n"

Formatter.currency.locale = .br
print(price.currency)  // "R$1,99\n"

Formatter.currency.locale = .uk
print(price.currency)  // "£1.99\n"

print(price.currencyBR)  // "R$1,99\n"
print(price.currencyUS)  // "$1.99\n"
person Leo Dabus    schedule 22.03.2017
comment
อย่าใช้ประเภทลอยตัวสำหรับสกุลเงิน ให้ใช้ทศนิยม - person adnako; 14.03.2018
comment
stackoverflow.com/questions/29782982/ - person Leo Dabus; 28.11.2019

รายละเอียด

  • Xcode 10.2.1 (10E1001), สวิฟท์ 5

สารละลาย

import Foundation

class CurrencyFormatter {
    static var outputFormatter = CurrencyFormatter.create()
    class func create(locale: Locale = Locale.current,
                      groupingSeparator: String? = nil,
                      decimalSeparator: String? = nil,
                      style: NumberFormatter.Style = NumberFormatter.Style.currency) -> NumberFormatter {
        let outputFormatter = NumberFormatter()
        outputFormatter.locale = locale
        outputFormatter.decimalSeparator = decimalSeparator ?? locale.decimalSeparator
        outputFormatter.groupingSeparator = groupingSeparator ?? locale.groupingSeparator
        outputFormatter.numberStyle = style
        return outputFormatter
    }
}

extension Numeric {
    func toCurrency(formatter: NumberFormatter = CurrencyFormatter.outputFormatter) -> String? {
        guard let num = self as? NSNumber else { return nil }
        var formatedSting = formatter.string(from: num)
        guard let locale = formatter.locale else { return formatedSting }
        if let separator = formatter.groupingSeparator, let localeValue = locale.groupingSeparator {
            formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator)
        }
        if let separator = formatter.decimalSeparator, let localeValue = locale.decimalSeparator {
            formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator)
        }
        return formatedSting
    }
}

การใช้งาน

let price = 12423.42
print(price.toCurrency() ?? "")

CurrencyFormatter.outputFormatter = CurrencyFormatter.create(style: .currencyISOCode)
print(price.toCurrency() ?? "nil")

CurrencyFormatter.outputFormatter = CurrencyFormatter.create(locale: Locale(identifier: "es_ES"))
print(price.toCurrency() ?? "nil")

CurrencyFormatter.outputFormatter = CurrencyFormatter.create(locale: Locale(identifier: "de_DE"), groupingSeparator: " ", style: .currencyISOCode)
print(price.toCurrency() ?? "nil")

CurrencyFormatter.outputFormatter = CurrencyFormatter.create(groupingSeparator: "_", decimalSeparator: ".", style: .currencyPlural)
print(price.toCurrency() ?? "nil")

let formatter = CurrencyFormatter.create(locale: Locale(identifier: "de_DE"), groupingSeparator: " ", decimalSeparator: ",", style: .currencyPlural)
print(price.toCurrency(formatter: formatter) ?? "nil")

ผลลัพธ์

$12,423.42
USD12,423.42
12.423,42 €
12 423,42 EUR
12_423.42 US dollars
12 423,42 Euro
person Vasily Bodnarchuk    schedule 08.12.2017

อัปเดตสำหรับ Swift 4 จากคำตอบของ @Michael Voccola:

extension Double {
    var asLocaleCurrency: String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = Locale.current

        let formattedString = formatter.string(from: self as NSNumber)
        return formattedString ?? ""
    }
}

หมายเหตุ: การไม่บังคับแกะ การบังคับแกะถือเป็นสิ่งชั่วร้าย

person kakubei    schedule 05.02.2019

ใช้ช่องข้อความ Swift 4 แล้ว

var value = 0    
currencyTextField.delegate = self

func numberFormatting(money: Int) -> String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = .current
        return formatter.string(from: money as NSNumber)!
    }

currencyTextField.text = formatter.string(from: 50 as NSNumber)!

func textFieldDidEndEditing(_ textField: UITextField) {
    value = textField.text
    textField.text = numberFormatting(money: Int(textField.text!) ?? 0 as! Int)
}

func textFieldDidBeginEditing(_ textField: UITextField) {
    textField.text = value
}
person Pengguna    schedule 12.02.2019

extension Float {
    var convertAsLocaleCurrency :String {
        var formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = Locale.current
        return formatter.string(from: self as NSNumber)!
    }
}

สิ่งนี้ใช้ได้กับ Swift 3.1 xcode 8.2.1

person du Phung    schedule 01.03.2017
comment
แม้ว่าข้อมูลโค้ดนี้จะยินดีและอาจให้ความช่วยเหลือได้ แต่ จะดีขึ้นมากหากมีคำอธิบายของวิธีการ และ ทำไม สิ่งนี้ช่วยแก้ปัญหาได้ จำไว้ว่าคุณกำลังตอบคำถามของผู้อ่านในอนาคต ไม่ใช่แค่คนที่ถามตอนนี้! โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบาย และระบุว่ามีข้อจำกัดและสมมติฐานใดบ้าง - person Toby Speight; 01.03.2017
comment
อย่าใช้ประเภทลอยตัวสำหรับสกุลเงิน ให้ใช้ทศนิยม - person adnako; 14.03.2018

สวิฟท์ 4

formatter.locale = Locale.current

หากคุณต้องการเปลี่ยนภาษาคุณสามารถทำได้เช่นนี้

formatter.locale = Locale.init(identifier: "id-ID") 

// นี่คือสถานที่สำหรับสถานที่ของอินโดนีเซีย หากคุณต้องการใช้ตามพื้นที่โทรศัพท์มือถือให้ใช้ตามที่ระบุไว้ด้านบน Locale.current

//MARK:- Complete code
let formatter = NumberFormatter()
formatter.numberStyle = .currency
    if let formattedTipAmount = formatter.string(from: Int(newString)! as 
NSNumber) { 
       yourtextfield.text = formattedTipAmount
}
person Shakeel Ahmed    schedule 16.04.2018

เพิ่มฟังก์ชันนี้

func addSeparateMarkForNumber(int: Int) -> String {
var string = ""
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .decimal
if let formattedTipAmount = formatter.string(from: int as NSNumber) {
    string = formattedTipAmount
}
return string
}

โดยใช้:

let giaTri = value as! Int
myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri)
person coders    schedule 13.05.2018