Home > database >  How to extract decimals from strings properly in this case?
How to extract decimals from strings properly in this case?

Time:10-27

From a port I receive lines one by one as follows:

"value:                 100.00 %  "
"value:                   100.00 %       "
" value:           01.12 %            "

ect.

Now in my C# code I need to extract the decimal numbers as AA.BB. But as you see a number with percentage sign AA.BB % can appear anywhere.

How can this be done with or without using regex?

CodePudding user response:

There are unspecified details about how you'd like this to behave. Here's one approach:

public static class InputLineParser
{
    public static decimal? ExtractValue(string input)
    {
        var segments = input.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
        if (segments.Length < 2) return default;
        if (decimal.TryParse(segments[1], out decimal result))
        {
            return result;
        }

        return default;
    }
}

This assumes some consistency within your inputs. If there are two values separated by spaces (excluding leading and trailing) then the second is parsed as a decimal. If there aren't two values or the second one can't be parsed it returns null. You could choose to add a condition that the first "value" must be the literal string "value:".

This is where unit tests are helpful. It's easy to write a few tests that take some inputs and assert that the expected values are returned. So if you want a different behavior but still want to be sure it works as expected in each case, just add or modify the test data.

[TestClass]
public class InputLineParserTests
{
    [DataTestMethod]
    [DataRow("value: 100.00 % ", 100)]
    [DataRow("value:                   100.00 %       ", 100)]
    [DataRow(" value:           01.12 %            ", 1.12)]
    public void ExtractValue_Returns_Expected_Value(string input, double expected)
    {
        decimal? actual = InputLineParser.ExtractValue(input);
        Assert.IsTrue(actual.HasValue);
        // The conversion from double to decimal is because the test
        // runner didn't like doing the conversion implicitly and
        // an attribute can't specify that the value is a decimal.
        Assert.AreEqual((decimal)expected, actual.Value);
    }

    [DataTestMethod]
    [DataRow("value:   ")]
    [DataRow("value: abc ")]
    [DataRow("   ")]
    public void ExtractValue_Returns_Null_When_No_Value_Found(string input)
    {
        decimal? actual = InputLineParser.ExtractValue(input);
        Assert.IsFalse(actual.HasValue);
    }
}

CodePudding user response:

I would use regex to solve this problem (regex c# documentation: https://www.c-sharpcorner.com/article/c-sharp-regex-examples/)

//some example string
string text = "My text has 25% chance of being right, and 75 % chance of being wrong! That's not great 7";
Console.WriteLine(text); // show text to console

// Create a pattern for number([0-9] ) and maybe space([ ]*) and '%' char or nothing ([%]|)
string pattern = @"\b[0-9] [ ]*([%]|)"; 
// Create a Regex with this pattern
Regex rg = new Regex(pattern);

// match the pattern (form an array of all found expressions)
MatchCollection matchedNumbers = rg.Matches(text);

// for each found member print it out
for (int count = 0; count < matchedNumbers.Count; count  )  
  Console.WriteLine(matchedNumbers[count].Value);

NOTE: they will be strings not numbers.
print should be:

25%
75 %
7

note this will not catch numbers with decimal points, for this you must make it a more complex pattern like this: string complex_pattern = @"\b[0-9] (([.][0-9] )|)[ ]*([%]|)";

CodePudding user response:

try this

var numberValue = new string( value.Where(ch=> (Char.IsDigit(ch) || ch=='.')).ToArray());

output

    100.00
    100.00
    01.12

CodePudding user response:

You can try regular expressions:

using System.Text.RegularExpressions;

...

decimal result = decimal.Parse(Regex.Match(source, @"[0-9]{2,3}\.[0-9]{2}").Value);

You can extract a method, e.g.

  public static bool TryExtract(string source, out decimal result) => double
    .TryParse(Regex.Match(source, @"[0-9]{2,3}\.[0-9]{2}").Value, out result);

which you can use as

if (TryExtract(source, out var result)) {
  // extracted in result 
}
else {
  // decimal is not found
}
  •  Tags:  
  • c#
  • Related