0

I would like to write a function that takes a currencyCode As String input parameter and outputs a custom currencyFormatString. My dilemma is deciding on the best (proper) way to do this. currencyCode is an ISO 4217 Currency Code (e.g. "USD", "GBP", "JPY", etc.), and I want to perform the following steps:

  1. Check for null or empty strings.
  2. Convert the code to the corresponding currency symbol (e.g. "$", "£", "¥" as in the above).
  3. Format the returning string with the appropriate symbol.

I have two cases for the formatting: with cents, and without. In the case of JPY, there are never cents, so in this case I would always return the non-cents (not nonsense, :P) format.

My latest idea is to create a Dictionary and populate it with the codes and symbols I need (FYI, we currently only need 6 codes/symbols and this very rarely changes). Is this a bad idea? Is there a better one? An XML file perhaps? I would love a code sample if you could. I'd provide one myself, but it's a scrambled mess of failed/less-than-ideal attempts at this point.

SOLUTIONS -- Based on hours of research, trial and error, and input from @tinstaafl.

'Method 1: Using Enumerable Type with Character Codes
'  Limitation: Does not support currency symbols with more than one character.
Public Module SLCurrency
    Enum ISOCurrency
        USD = 36
        CAD = 36
        AUD = 36
        EUR = 8364
        GBP = 163
        JPY = 165
    End Enum

    Public Function GetCurrencyFormat(ByVal currencyCode As String, ByVal withCents As Boolean) As String
        Dim _numberFormatString, _currency As New ISOCurrency

        [Enum].TryParse(Of ISOCurrency)(currencyCode, _currency)

        If withCents AndAlso Not _curr.Equals(ISOCurrency.JPY) Then
            _numberFormatString = "{0}* #,##0.00;[Red]{0}* (#,##0.00);{0}* ""-"";@"
        Else
            _numberFormatString = "{0}* #,##0;[Red]{0}* (#,##0);{0}* ""-"";@"
        End If

        Return String.Format(_numberFormatString, ChrW(_currency).ToString.Trim({ChrW(0)}))
    End Function
End Module
'Method 2: Using a Dictionary of Currency Codes (key) and Symbols
'  Advantage: Support currency symbols with more than one character,
'  but is not quite as clean and can be more complex to implement.
Public Module SLCurrency
    Dim CurrencyDict As New Dictionary(Of String, String) From {
        {"USD", "$"}, {"CAD", "$"}, {"AUD", "$"}, {"EUR", "€"}, {"GBP", "£"}, {"JPY", "¥"}
    }

    Public Function GetCurrencyFormat(ByVal currencyCode As String, ByVal withCents As Boolean) As String
        Dim _numberFormatString, _currency As String
        _currency = String.Empty

        CurrencyDict.TryGetValue(currencyCode, _currency)

        If withCents AndAlso Not _currency.Equals("JPY") Then
            _numberFormatString = "{0}* #,##0.00;[Red]{0}* (#,##0.00);{0}* ""-"";@"
        Else
            _numberFormatString = "{0}* #,##0;[Red]{0}* (#,##0);{0}* ""-"";@"
        End If

        Return String.Format(_numberFormatString, _currency)
    End Function
End Module

I always welcome comments on my solutions. It helps me become a better programmer. :)

At this point, I think I'll go with Method 1 to keep the code a bit simpler as I do not anticipate a need for the added complexity to support longer currency symbols, especially since most of them are very obscure currencies which a business would be highly unlikely to ever accept as payment anyway.

Chiramisu
  • 4,687
  • 7
  • 47
  • 77

2 Answers2

1

One simple way would be to create an enum with the value being the character code of the symbol:

Enum CurrencySymbols
    USD = 36
    GBP = 163
    JPY = 165
End Enum

A simple function to convert a string to enum value and return it as a string, could look something like this:

Private Function GetCurr(Input As String) As String
    Dim CurrCode As New CurrencySymbols
    If [Enum].TryParse(Of CurrencySymbols)(Input, CurrCode) Then
        GetCurr = ChrW(CurrCode)
    Else
        GetCurr = ChrW(0)
    End If
End Function

If the string is invalid this will return string with a character with code 0

Chiramisu
  • 4,687
  • 7
  • 47
  • 77
tinstaafl
  • 6,908
  • 2
  • 15
  • 22
  • Unless there's some programming magic I haven't learned yet to convert a string input to a corresponding Enum, this isn't going to work. I appreciate the thought though. :) – Chiramisu Oct 29 '13 at 07:52
  • The Enum class has available methods – tinstaafl Oct 29 '13 at 14:01
  • Ok, cool, that could definitely help someone and is worth noting. However, in my case, I need to take the ISO Currency Code (as a string), NOT Character Code (as an Enum), and convert it to the Currency Symbol. Then build my Currency Format string. FYI, this is for use with the SpreedsheetLight library, namely the `SLStyle.FormatCode` property. :) – Chiramisu Oct 29 '13 at 15:31
  • The function I showed you takes a string("USD","GBP" or "JPY"), as per your post, and returns a string with the currency symbol("$","£" or "¥") as the only character in that string. From there it should be a simple matter to build the format string incorporating the return from this function. – tinstaafl Oct 29 '13 at 16:55
  • Ok, that meets my immediate need, however, how do you propose to handle [Currency Symbols](http://www.xe.com/symbols.php) with more than one character? Remember, I would like it to be extensible. :) – Chiramisu Oct 29 '13 at 18:54
  • Crap, yet another issue. When I do a `String.Format("{0}", ChrW(0))`, I get a string with a space character in it which cannot be Trimmed. I need {0} to be replaced with the string value "" instead of the char value " " where ChrW(0). How can this be achieved? – Chiramisu Oct 29 '13 at 19:54
  • You can set ChrW(0) as the trim value `.Trim({ChrW(0), " "c})`. And since the argument is an array you can add other characters in there as well. for instance that statement will trim all leading occurrences of ChrW(0) and Spaces – tinstaafl Oct 29 '13 at 19:58
  • 1
    To include the complexity of Currency Symbols with multiple characters, you'll probably have to go with a more complex structure. A Dictionary(Of String,List(Of Byte)) and a TextFile loaded as a resource to load the dictionary, would work. If your text file is an inclusive list you can use a setting to know which codes to load. This way you only have to re-compile the app if the list becomes too outdated. – tinstaafl Oct 29 '13 at 20:11
0

It is up to you to decide which solution suits you and your task better, but one thing is for sure: you need a functionality somewhere which initializes these currencies, which is called at the initialization phase of your application and then you can use any currency through a getter.

Of course, you can use a dictionary. Also, you can use an XML file if you are sure no untrusted people will access it. Finally, you can store all these information into a database as well. So everything depends on your decision.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • Do you have a recommendation on how to implement the initialization as you mentioned? If you could give me a code snippet to get me pointed in the right direction for that as well as maybe a dictionary implementation that would be very helpful. I'm especially interested in the "best practice" solution that will create an extensible code base. Best. :) – Chiramisu Oct 29 '13 at 07:56