web-dev-qa-db-ja.com

swiftで通貨コードから通貨記号を取得します

Swift(macOS)を使用して、対応する通貨コードの通貨記号を取得するにはどうすればよいですか?.

例:

  • ユーロ=€1.00
  • USD = 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

または..より良い方法はありますか?

21
Geek20

少し遅いですが、これは私が通貨記号にUS $などの代わりに$を取得するために使用したソリューションです。

/*
 * 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を形成することにより、新しい国固有のロケールを作成します。次に、通貨記号を再度取得しようとします。

Swift 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)
}
29
Pancho

これを行う適切な方法は、フレームワークに情報を提供させることです。

localeIdentifierFromComponents()と呼ばれるNSLocaleのあいまいなクラスメソッドを使用して、その情報を取得できます。このメソッドは、ロケールのさまざまな属性を定義するディクショナリを取得し、実際に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$"
11
Dave DeLong

答えは遅いかもしれませんが、うまくいけば、これが根本的な原因を明らかにするのに役立ちます。

問題

  • 通貨コードはロケールと地域を意味しません

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はイヌクティトゥット語ですが、なぜ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文字の記号はありません。

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. 直感的に、通貨コードに複数の異なるシンボルがある場合、1文字のシンボルのアプローチでは誤ったシンボルが表示される可能性があると思いますが、そのようなケースを見たことはありません。
  2. 毎回これを計算するのは大変な作業なので、ユーザーが通貨設定を設定するときは、計算された結果を保存し、ルックアップごとにその結果を使用するのが賢明です
9
tsuz

ここでの提案をすべて組み合わせて改善し、将来の読者(あなた)にドロップイン(コピー/貼り付け)ソリューションを提供しました。

独自のローカルキャッシュを持ち、大文字と小文字を区別せず、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) }
}
5
Gunhan
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) 
}
3
that guy

不完全解決策$ の代わりに 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;
}
3
mpatzer

あなたはこれを試すことができます:

let formatter = NSNumberFormatter()

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

Swift 4バージョン Panchoの回答、String.charactersは非推奨になりました。

文字列に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
Agent Smith

Swiftで通貨記号を取得するだけです。

let locale = Locale.current // currency symbol from current location
//let locale = Locale(identifier: "fr_FR") // or you could specify the locale e.g fr_FR, en_US etc
let currencySymbol = locale.currencySymbol!

print("\(currencySymbol)")
0
fs_tigre
let countryCode = (Locale.current as NSLocale).object(forKey: .currencySymbol) as? String ?? "$"

上記では現在の通貨記号が表示されますが、英国の場合は次のようになります=£Apple Doc

0
iOS_Engineer