From ebbf8bbe36744e82feb42bf468dc649d5249bf63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Wo=C5=9B?= Date: Mon, 14 Sep 2020 19:29:03 +0200 Subject: [PATCH] Implement new initialization function - NewFromFormattedString (#184) * Implement new initialization function - NewFromFormattedString * Redefine docstring --- decimal.go | 25 +++++++++++++++++++++++++ decimal_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/decimal.go b/decimal.go index df44567..c0404f1 100644 --- a/decimal.go +++ b/decimal.go @@ -22,6 +22,7 @@ import ( "fmt" "math" "math/big" + "regexp" "strconv" "strings" ) @@ -176,6 +177,30 @@ func NewFromString(value string) (Decimal, error) { }, nil } +// NewFromFormattedString returns a new Decimal from a formatted string representation. +// The second argument - replRegexp, is a regular expression that is used to find characters that should be +// removed from given decimal string representation. All matched characters will be replaced with an empty string. +// +// Example: +// +// r := regexp.MustCompile("[$,]") +// d1, err := NewFromFormattedString("$5,125.99", r) +// +// r2 := regexp.MustCompile("[_]") +// d2, err := NewFromFormattedString("1_000_000", r2) +// +// r3 := regexp.MustCompile("[USD\\s]") +// d3, err := NewFromFormattedString("5000 USD", r3) +// +func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) { + parsedValue := replRegexp.ReplaceAllString(value, "") + d, err := NewFromString(parsedValue) + if err != nil { + return Decimal{}, err + } + return d, nil +} + // RequireFromString returns a new Decimal from a string representation // or panics if NewFromString would have returned an error. // diff --git a/decimal_test.go b/decimal_test.go index c07b88a..d7ec5e4 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -9,6 +9,7 @@ import ( "math/big" "math/rand" "reflect" + "regexp" "strconv" "strings" "testing" @@ -240,6 +241,35 @@ func TestNewFromString(t *testing.T) { } } +func TestNewFromFormattedString(t *testing.T) { + for _, testCase := range []struct { + Formatted string + Expected string + ReplRegex *regexp.Regexp + }{ + {"$10.99", "10.99", regexp.MustCompile("[$]")}, + {"$ 12.1", "12.1", regexp.MustCompile("[$\\s]")}, + {"$61,690.99", "61690.99", regexp.MustCompile("[$,]")}, + {"1_000_000.00", "1000000.00", regexp.MustCompile("[_]")}, + {"41,410.00", "41410.00", regexp.MustCompile("[,]")}, + {"5200 USD", "5200", regexp.MustCompile("[USD\\s]")}, + } { + dFormatted, err := NewFromFormattedString(testCase.Formatted, testCase.ReplRegex) + if err != nil { + t.Fatal(err) + } + + dExact, err := NewFromString(testCase.Expected) + if err != nil { + t.Fatal(err) + } + + if !dFormatted.Equal(dExact) { + t.Errorf("expect %s, got %s", dExact, dFormatted) + } + } +} + func TestFloat64(t *testing.T) { for _, x := range testTable { if x.inexact == "" || x.inexact == "-" { @@ -294,6 +324,11 @@ func TestNewFromStringErrs(t *testing.T) { "123.456Easdf", "123.456e" + strconv.FormatInt(math.MinInt64, 10), "123.456e" + strconv.FormatInt(math.MinInt32, 10), + "512.99 USD", + "$99.99", + "51,850.00", + "20_000_000.00", + "$20_000_000.00", } for _, s := range tests {