Search code examples
c#regexstringrounding

Round parts of math formula as string


I got a string from an XML file like:

abs((0+2.315)*((-0.008)-0) + (2.315+2.323)*(1.09-(-0.008)) + (2.323+0.007)*(1.076-1.09) + (0.007+0)*(0-1.076)) * 0.500

I would like to scan the string for numbers and round all numbers up or down to 2 decimal places.

My code filters correctly, but did nothing:

string trim = "abs((0+2.315)*((-0.008)-0) + (2.315+2.323)*(1.09-(-0.008)) + (2.323+0.007)*(1.076-1.09) + (0.007+0)*(0-1.076)) * 0.500";
string pattern = @"(\d*\.\d\d)\d*";
trim = Regex.Replace(trim, pattern, Math.Round((Decimal)Convert.ToDecimal("$1"), 2).ToString("0.00"));

Solution

  • The "$1" reference isn't available in that fashion. What you can do is use the Replace(String, String, MatchEvaluator) overload like this:

    public static string RoundedStringNumber(Match match)
    {
        if (Decimal.TryParse(match.Value, out decimal d)) {
            return Math.Round(d, 2).ToString("0.00");
        }
        return match.Value;
    }
    
    static void Main(string[] args)
    {
        string trim = "abs((0+2.315)*((-0.008)-0) + (2.315+2.323)*(1.09-(-0.008)) + (2.323+0.007)*(1.076-1.09) + (0.007+0)*(0-1.076)) * 0.500";
        string pattern = @"(\d*\.\d\d)\d*";
        MatchEvaluator evaluator = new MatchEvaluator(RoundedStringNumber);
        trim = Regex.Replace(trim, pattern, evaluator);
    
        Console.WriteLine(trim);
    
        Console.ReadLine();
    }
    

    Outputs:

    abs((0+2.32)*((-0.01)-0) + (2.32+2.32)*(1.09-(-0.01)) + (2.32+0.01)*(1.08-1.09) + (0.01+0)*(0-1.08)) * 0.50
    

    Note that if you wanted to use a different rounding, e.g., MidpointRounding.ToPositiveInfinity, then you would need to include the minus sign in the regex capture.

    Additionally, if you need to change the formatting of the numbers from one country settings to another, you can do it like this:

    public static string RoundedStringNumber(Match match)
    {
        var cultureIn = CultureInfo.GetCultureInfo("en-US");
        var cultureOut = CultureInfo.GetCultureInfo("fr-FR");
    
        if (Decimal.TryParse(match.Value, cultureIn, out decimal d)) {
            return Math.Round(d, 2).ToString("0.00", cultureOut);
        }
        return match.Value;
    }
    

    Which, for the same input as before, outputs:

    abs((0+2,32)*((-0,01)-0) + (2,32+2,32)*(1,09-(-0,01)) + (2,32+0,01)*(1,08-1,09) + (0,01+0)*(0-1,08)) * 0,50