将字符串转换为十进制但保留数字部分

时间:2015-03-13 13:20:21

标签: c# string decimal

有没有办法在C#中将字符串转换为十进制但忽略尾随“垃圾”?即像PHP的floatval()或C strtod()

e.g。 将字符串"2974.23abcdefs"转换为小数2974.23

4 个答案:

答案 0 :(得分:0)

正如其他人所提到的那样,对于你在PHP中可以做的事情没有确切的替代,我认为,这是有充分理由的。在Web应用程序的场景中,我不确定如果我最后接受带有垃圾的小数,我实际上想将其视为有效数据,但这只是我的看法。

您可以做的是定义一个捕获小数的正则表达式,并认识到这种情况正在发生。我发现这更安全可靠。

显然,正则表达式可以改进但这只是一个简单的例子: -

var match = Regex.Match("2974.23abcdefs", "^([0-9]+\\.[0-9]+)(.+)?$");
if (match.Success)
{
    // See the also the link below for using Decimal.TryParse
    Console.WriteLine(Convert.ToDecimal(match.Groups[1].Value));
}

请参阅https://msdn.microsoft.com/en-us/library/system.decimal.tryparse%28v=vs.110%29.aspx了解我转换为小数的首选方法。这将确保您正在处理正则表达式的输出,以了解Decimal的构成方式

有关正则表达式的更多信息,请参阅https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex%28v=vs.110%29.aspx

答案 1 :(得分:0)

作为 first second ,第三次尝试,这应该是:

static double Parse(string str, IFormatProvider provider = null)
{
    if (str == string.Empty)
    {
        return 0;
    }

    if (provider == null)
    {
        provider = CultureInfo.CurrentCulture;
    }

    NumberFormatInfo nfi = NumberFormatInfo.GetInstance(provider);

    // [ws][sign][integral-digits[,]]integral-digits[.[fractional-digits]][E[sign]exponential-digits][ws]
    string ws = @"\s*";
    string sign = @"(" + Regex.Escape(nfi.PositiveSign) + "|" + Regex.Escape(nfi.NegativeSign) + ")?";
    string integralDigits1 = "([0-9](" + Regex.Escape(nfi.NumberGroupSeparator) + ")*)*";
    string integralDigits2 = "[0-9]+";
    string fractionalDigits = "(" + Regex.Escape(nfi.NumberDecimalSeparator) + "[0-9]*)?";
    string exponentialDigits = "([Ee]" + sign + "[0-9]+)?";

    var rx = new Regex(ws + sign + integralDigits1 + integralDigits2 + fractionalDigits + exponentialDigits);

    string match = rx.Match(str).ToString();

    if (match == string.Empty)
    {
        return 0;
    }

    return double.Parse(match, provider);
}

请注意,组合正则表达式非常复杂,因为有各种各样的"部分"在已写入字符串的完整双精度数中。

来自MSDN:

  

[WS] [符号] [积分位数[,]]积分位数[[小数位] [E [符号]指数位数] [WS]

如果它们太大,还有一些数字会使这个函数崩溃。因此,传递new string('9', 1000)会使double.Parse抛出异常。

使用它像:

double num = Parse("        +1,0.1234E+12abcdefgh", CultureInfo.InvariantCulture);

double num = Parse("        +1,,,,,0.1234E+12abcdefgh");

(如果您不需要配置文化,请使用CultureInfo.CurrentCulture

答案 2 :(得分:0)

这可以工作,但只处理数字和当前文化的小数分隔符:

string input = "2974.23abcdefs";
decimal d;
char decSep = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0]; // there is no culture with a decimal-separator that has more than one letter so this isn't harmful
if(!string.IsNullOrEmpty(input) && Char.IsDigit(input[0]))
{
    string number = string.Concat(input.TakeWhile(c => Char.IsDigit(c) || decSep == c));
    bool validDecimal = decimal.TryParse(number, out d);
    Console.WriteLine("Valid? {0} Parsed to: {1}", validDecimal, d);
}

由于我们在德国使用,作为小数点分隔符,因此我得到的结果与使用.作为分隔符的人不同。得到2974.23,我得到2974

答案 3 :(得分:0)

有很多方法可以做到这一点。我建议先使用正则表达式,然后使用decimal.TryParse()

这是一个正则表达式,它捕获字符串开头的浮点数,如-123.43或仅1234.56或123456:

^([+-][0-9]+\.?[0-9]*).*$ 

将它放入C#看起来像这样:

    // Step 1: Getting some input
    String input = "123.4533wefwe";

    // Step 2: Get rid of the trail 
    Regex r = new Regex(@"^([+-][0-9]+\.?[0-9]*).*$", RegexOptions.IgnoreCase);

    MatchCollection matches = r.Matches(input);
    if (matches.Count > 0) {
        Match match = matches[0];
        GroupCollection groups = match.Groups;

        // Step 3: create a real decimal from the string
        decimal i;
        NumberStyles style;
        CultureInfo culture;
        style = NumberStyles.Number;
        culture = CultureInfo.CreateSpecificCulture("en-GB");

        String matchedNumber = groups[1].Value;

        if (decimal.TryParse(matchedNumber, style, culture, out i)) {

           // Step 4: giving back the result: 
           Console.WriteLine("Parsed decimal: " + i);
        }            
    }

这个输出是:

Parsed decimal: 123.4533

备注:如果要解析包含指数表示法的实数浮点数文字,所有这些似乎都会成为一个更大的问题。然后,需要几个阶段的铸造。