使用swift从货币代码中获取货币符号

问题描述 投票:17回答:9

如何使用Swift(macOS)获取相应货币代码的货币符号。

例:

  • EUR =€1.00
  • 美元= 1.00美元
  • CAD = $ 1.00
  • GBP =£1.00

我的代码:

var formatter = NSNumberFormatter()
formatter.currencySymbol = getSymbol(currencyCode)
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
let number = NSNumber(double: (amount as NSString).doubleValue)
let amountWithSymbol = formatter.stringFromNumber(number)!

getSymbol(_ currencyCode: String) -> String

或者,还有更好的方法?

macos swift cocoa currency
9个回答
25
投票

有点晚了,但这是我用来获得货币符号的$而不是美元等的解决方案。

/*
 * Bear in mind not every currency have a corresponding symbol. 
 *
 * EXAMPLE TABLE
 *
 * currency code | Country & Currency | Currency Symbol
 *
 *      BGN      |   Bulgarian lev    |      лв   
 *      HRK      |   Croatian Kuna    |      kn
 *      CZK      |   Czech  Koruna    |      Kč
 *      EUR      |       EU Euro      |      €
 *      USD      |     US Dollar      |      $
 *      GBP      |   British Pound    |      £
 */

func getSymbol(forCurrencyCode code: String) -> String? {
   let locale = NSLocale(localeIdentifier: code)
   return locale.displayNameForKey(NSLocaleCurrencySymbol, value: code)
}

基本上,这会从您的货币代码创建NSLocale并获取货币的显示属性。如果结果与货币代码匹配,例如SEK,它将通过从货币代码中删除最后一个字符并附加“_en”来形成SE_en来创建新的国家/地区特定区域设置。然后它将尝试再次获得货币符号。

斯威夫特3和4

func getSymbol(forCurrencyCode code: String) -> String? {
    let locale = NSLocale(localeIdentifier: code)
    if locale.displayName(forKey: .currencySymbol, value: code) == code {
        let newlocale = NSLocale(localeIdentifier: code.dropLast() + "_en")
        return newlocale.displayName(forKey: .currencySymbol, value: code)
    }
    return locale.displayName(forKey: .currencySymbol, value: code)
}

9
投票

正确的方法是让框架为您提供信息。

您可以在NSLocale上使用名为localeIdentifierFromComponents()的模糊类方法检索该信息。该方法将采用定义语言环境的各种属性的字典,然后返回可用于实际构造NSLocale实例的标识符。一旦你有NSLocale,你可以问它的CurrencySymbol,像这样:

let currencyCode = "CAD"

let localeComponents = [NSLocaleCurrencyCode: currencyCode]
let localeIdentifier = NSLocale.localeIdentifierFromComponents(localeComponents)
let locale = NSLocale(localeIdentifier: localeIdentifier)
let currencySymbol = locale.objectForKey(NSLocaleCurrencySymbol) as! String
// currencySymbol is "CA$"

5
投票

答案可能会迟到,但希望这有助于澄清根本原因。

问题

  • 货币代码并不意味着区域设置和区域

CAD成为CA $的原因可能是因为NSLocale查找了第一个匹配的货币代码,而对于CAD,这些是localeIdentifiers的匹配NSLocale.availableLocaleIdentifiers

1. Optional("CA$") Optional("CA") iu_CA
2. Optional("$") Optional("CA") fr_CA
3. Optional("$") Optional("CA") en_CA

iu_CA是Inuktitut,但我不确定为什么它被列为CA$,但我希望这一点很明确。

同样在CNY(人民币):

1. Optional("CN¥") Optional("CN") en_CN
2. Optional("¥") Optional("CN") yue_CN
3. Optional("¥") Optional("CN") bo_CN
4. Optional("¥") Optional("CN") zh_CN
5. Optional("¥") Optional("CN") ug_CN
6. Optional("¥") Optional("CN") ii_CN

在en_CN时显示CN¥的原因可能是因为JPY也使用¥。

在CHF(瑞士法郎)中,他们没有单字母符号:

1. Optional("CHF") Optional("LI") gsw_LI
2. Optional("CHF") Optional("CH") de_CH
...
9. Optional("CHF") Optional("CH") en_CH
10. Optional("CHF") Optional("CH") it_CH

许多应用程序各不相同,但这是我为我的应用程序感到满意的步骤:

  1. 使用所有区域设置标识符中的货币代码查找查找匹配的区域设置候选
  2. 从候选人中选择最短的符号
  3. 将符号存储在某处,以便不必每次都计算它

履行

func getSymbolForCurrencyCode(code: String) -> String {
    var candidates: [String] = []
    let locales: [String] = NSLocale.availableLocaleIdentifiers
    for localeID in locales {
        guard let symbol = findMatchingSymbol(localeID: localeID, currencyCode: code) else {
            continue
        }
        if symbol.count == 1 {
            return symbol
        }
        candidates.append(symbol)
    }
    let sorted = sortAscByLength(list: candidates)
    if sorted.count < 1 {
        return ""
    }
    return sorted[0]
}

func findMatchingSymbol(localeID: String, currencyCode: String) -> String? {
    let locale = Locale(identifier: localeID as String)
    guard let code = locale.currencyCode else {
        return nil
    }
    if code != currencyCode {
        return nil
    }
    guard let symbol = locale.currencySymbol else {
        return nil
    }
    return symbol
}

func sortAscByLength(list: [String]) -> [String] {
    return list.sorted(by: { $0.count < $1.count })
}

用法

let usd = getSymbolForCurrencyCode(code: "USD")
let jpy = getSymbolForCurrencyCode(code: "JPY")
let cny = getSymbolForCurrencyCode(code: "CNY")
let cad = getSymbolForCurrencyCode(code: "CAD")
let uah = getSymbolForCurrencyCode(code: "UAH")
let krw = getSymbolForCurrencyCode(code: "KRW")
let zar = getSymbolForCurrencyCode(code: "ZAR")
let chf = getSymbolForCurrencyCode(code: "CHF")
let all = [usd, jpy, cny, cad, uah, krw, zar, chf]

(lldb) po all
▿ 8 elements
  - 0 : "$"
  - 1 : "¥"
  - 2 : "¥"
  - 3 : "$"
  - 4 : "₴"
  - 5 : "₩"
  - 6 : "R"
  - 7 : "CHF"

问题

  1. 本能地,我看到如果货币代码有多个不同的符号,单字母符号方法可能会显示不正确的符号,但我没有看到这种情况。
  2. 每次计算都是繁重的,所以当用户设置他们的货币设置时,最好存储计算结果并在每次查找时使用该结果

3
投票

我发现获得$而不是US$CA$的不完美解决方案是尝试首先将用户的当前区域设置与货币代码相匹配。这适用于您正在构建移动应用并且API根据该用户帐户中的设置向您发送货币代码的情况。对我们来说,商业案例是99%的用户在后端帐户中设置相同的货币代码(USDCADEUR等),我们从他们的移动应用程序中获取信息。我们以用户期望看到它的方式显示货币(即$50.56而不是US$ 50.56)。

Objective-C的

- (NSLocale *)localeFromCurrencyCode:(NSString *)currencyCode {
    NSLocale *locale = [NSLocale currentLocale];
    if (![locale.currencyCode isEqualToString:currencyCode]) {
        NSDictionary *localeInfo = @{NSLocaleCurrencyCode:currencyCode};
        locale = [[NSLocale alloc] initWithLocaleIdentifier:[NSLocale localeIdentifierFromComponents:localeInfo]];
    }
    return locale;
}

迅速

func locale(from currencyCode: String) -> Locale {
    var locale = Locale.current
    if (locale.currencyCode != currencyCode) {
        let identifier = NSLocale.localeIdentifier(fromComponents: [NSLocale.Key.currencyCode.rawValue: currencyCode])
        locale = NSLocale(localeIdentifier: identifier) as Locale
    }
    return locale;
}

2
投票
SWIFT4 
//converting USD to $a and GBP to £ 
viewDidLoad() 
{ 
 print(getSymbolForCurrencyCode(code: "USD")!) // prints $ 
 print(getSymbolForCurrencyCode(code: "GBP")!) //prints £ 
}

func getSymbolForCurrencyCode(code: String) -> String? 
{ 
  let locale = NSLocale(localeIdentifier: code)
  return locale.displayName(forKey: NSLocale.Key.currencySymbol, value: code) 
}

2
投票

我结合并改进了所有的建议,为未来的读者(你)提供了一个插入(复制/粘贴)解决方案。

它有自己的本地缓存,不区分大小写,并有一个扩展方法来为String提供链接。 Swift 4/5准备好了。

如何使用:

"USD".currencySymbol //returns "$"
//OR
Currency.shared.findSymbol(currencyCode: "TRY") //returns "₺"

测试:

    XCTAssertEqual("$", "USD".currencySymbol)
    XCTAssertEqual("₺", "TRY".currencySymbol)
    XCTAssertEqual("€", "EUR".currencySymbol)
    XCTAssertEqual("", "ASDF".currencySymbol)

码:

class Currency {
    static let shared: Currency = Currency()

    private var cache: [String:String] = [:]

    func findSymbol(currencyCode:String) -> String {
        if let hit = cache[currencyCode] { return hit }
        guard currencyCode.count < 4 else { return "" }

        let symbol = findSymbolBy(currencyCode)
        cache[currencyCode] = symbol

        return symbol
    }

    private func findSymbolBy(_ currencyCode: String) -> String {
        var candidates: [String] = []
        let locales = NSLocale.availableLocaleIdentifiers

        for localeId in locales {
            guard let symbol = findSymbolBy(localeId, currencyCode) else { continue }
            if symbol.count == 1 { return symbol }
            candidates.append(symbol)
        }

        return candidates.sorted(by: { $0.count < $1.count }).first ?? ""
    }

    private func findSymbolBy(_ localeId: String, _ currencyCode: String) -> String? {
        let locale = Locale(identifier: localeId)
        return currencyCode.caseInsensitiveCompare(locale.currencyCode ?? "") == .orderedSame
            ? locale.currencySymbol : nil
    }
}

extension String {
    var currencySymbol: String { return Currency.shared.findSymbol(currencyCode: self) }
}

1
投票

你可以试试这个:

let formatter = NSNumberFormatter()

for locale in NSLocale.availableLocaleIdentifiers() {
    formatter.locale = NSLocale(localeIdentifier: locale)
    print("\(formatter.currencyCode) =  \(formatter.currencySymbol)")
}

1
投票

Swift 4版本的Pancho的答案,因为现在不推荐使用String.characters。

我们可以简单地在String上应用dropLast()。

func getCurrencySymbol(from currencyCode: String) -> String? {

    let locale = NSLocale(localeIdentifier: currencyCode)
    if locale.displayName(forKey: .currencySymbol, value: currencyCode) == currencyCode {
        let newlocale = NSLocale(localeIdentifier: currencyCode.dropLast() + "_en")
        return newlocale.displayName(forKey: .currencySymbol, value: currencyCode)
    }
    return locale.displayName(forKey: .currencySymbol, value: currencyCode)
}

-1
投票

Swift 4.2

// Currency Codes
Locale.isoCurrencyCodes

// Results ⬇︎
// ["ADP", "AED", "AFA", "AFN", "ALK", "ALL", "AMD", "ANG", "AOA", "AOK", "AON", "AOR", "ARA", "ARL", "ARM", "ARP", "ARS", "ATS", "AUD", "AWG", "AZM", "AZN", "BAD", "BAM", "BAN", "BBD", "BDT", "BEC", "BEF", "BEL", "BGL", "BGM", "BGN", "BGO", "BHD", "BIF", "BMD", "BND", "BOB", "BOL", "BOP", "BOV", "BRB", "BRC", "BRE", "BRL", "BRN", "BRR", "BRZ", "BSD", "BTN", "BUK", "BWP", "BYB", "BYN", "BYR", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLE", "CLF", "CLP", "CNH", "CNX", "CNY", "COP", "COU", "CRC", "CSD", "CSK", "CUC", "CUP", "CVE", "CYP", "CZK", "DDM", "DEM", "DJF", "DKK", "DOP", "DZD", "ECS", "ECV", "EEK", "EGP", "EQE", "ERN", "ESA", "ESB", "ESP", "ETB", "EUR", "FIM", "FJD", "FKP", "FRF", "GBP", "GEK", "GEL", "GHC", "GHS", "GIP", "GMD", "GNF", "GNS", "GQE", "GRD", "GTQ", "GWE", "GWP", "GYD", "HKD", "HNL", "HRD", "HRK", "HTG", "HUF", "IDR", "IEP", "ILP", "ILR", "ILS", "INR", "IQD", "IRR", "ISJ", "ISK", "ITL", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRH", "KRO", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LSM", "LTL", "LTT", "LUC", "LUF", "LUL", "LVL", "LVR", "LYD", "MAD", "MAF", "MCF", "MDC", "MDL", "MGA", "MGF", "MKD", "MKN", "MLF", "MMK", "MNT", "MOP", "MRO", "MRU", "MTL", "MTP", "MUR", "MVP", "MVR", "MWK", "MXN", "MXP", "MXV", "MYR", "MZE", "MZM", "MZN", "NAD", "NGN", "NIC", "NIO", "NLG", "NOK", "NPR", "NZD", "OMR", "PAB", "PEI", "PEN", "PES", "PGK", "PHP", "PKR", "PLN", "PLZ", "PTE", "PYG", "QAR", "RHD", "ROL", "RON", "RSD", "RUB", "RUR", "RWF", "SAR", "SBD", "SCR", "SDD", "SDG", "SDP", "SEK", "SGD", "SHP", "SIT", "SKK", "SLL", "SOS", "SRD", "SRG", "SSP", "STD", "STN", "SUR", "SVC", "SYP", "SZL", "THB", "TJR", "TJS", "TMM", "TMT", "TND", "TOP", "TPE", "TRL", "TRY", "TTD", "TWD", "TZS", "UAH", "UAK", "UGS", "UGX", "USD", "USN", "USS", "UYI", "UYP", "UYU", "UZS", "VEB", "VEF", "VND", "VNN", "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XEU", "XFO", "XFU", "XOF", "XPD", "XPF", "XPT", "XRE", "XSU", "XTS", "XUA", "XXX", "YDD", "YER", "YUD", "YUM", "YUN", "YUR", "ZAL", "ZAR", "ZMK", "ZMW", "ZRN", "ZRZ", "ZWD", "ZWL", "ZWR"]


// Validation
let currencyCode = "USD"
let isValid = 0 < Locale.isoCurrencyCodes.filter { $0 == currencyCode }.count
© www.soinside.com 2019 - 2024. All rights reserved.