decimal.TryParse很高兴接受格式错误的数字字符串

Mik*_*ill 10 c# parsing

有没有办法让C#TryParse()函数更严格一些?

现在,如果你传入一个包含数字,正确的十进制和千位分隔符的字符串,它通常似乎接受它们,即使格式没有意义,例如: 123''345'678

如果数字格式不正确,我正在寻找一种TryParse 不成功的方法.

所以,我的总部设在苏黎世,如果我这样做:

decimal exampleNumber = 1234567.89m;
Trace.WriteLine(string.Format("Value {0} gets formatted as: \"{1:N}\"", exampleNumber, exampleNumber));
Run Code Online (Sandbox Code Playgroud)

...然后,根据我的区域设置,我得到了......

Value 1234567.89 gets formatted as: "1'234'567.89"
Run Code Online (Sandbox Code Playgroud)

所以你可以看到,对于我的区域,小数位字符是一个句号,千分隔符是一个撇号.

现在,让我们创建一个简单的函数来测试是否string可以将其解析为decimal:

private void ParseTest(string str)
{
    decimal val = 0;
    if (decimal.TryParse(str, out val))
        Trace.WriteLine(string.Format("Parsed \"{0}\" as {1}", str, val));
    else
        Trace.WriteLine(string.Format("Couldn't parse: \"{0}\"", str));
}
Run Code Online (Sandbox Code Playgroud)

好吧,让我们用几个字符串来调用这个函数.

您认为以下哪个字符串可以被此函数成功解析?

以下是我得到的结果:

ParseTest("123345.67");         //  1. Parsed "123345.67" as 123345.67
ParseTest("123'345.67");        //  2. Parsed "123'345.67" as 123345.67
ParseTest("123'345'6.78");      //  3. Parsed "123'345'6.78" as 1233456.78
ParseTest("1''23'345'678");     //  4. Parsed "1''23'345'678" as 123345678
ParseTest("'1''23'345'678");    //  5. Couldn't parse: "'1''23'345'678"
ParseTest("123''345'678");      //  6. Parsed "123''345'678" as 123345678
ParseTest("123'4'5'6.7.89");    //  7. Couldn't parse: "123'4'5'6.7.89"
ParseTest("'12'3'45'678");      //  8. Couldn't parse: "'12'3'45'678"
Run Code Online (Sandbox Code Playgroud)

我想你可以看到我的观点.

对我来说,只有前两个字符串才能成功解析.其他人应该都失败了,因为他们在千分之后没有3位数,或者有两个撇号.

即使我将其更改为ParseTest更具体,结果也完全相同.(例如,它乐意接受" 123''345'678"作为有效小数.)

private void ParseTest(string str)
{
    decimal val = 0;
    var styles = (NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands);

    if (decimal.TryParse(str, styles, CultureInfo.CurrentCulture, out val))
        Trace.WriteLine(string.Format("Parsed \"{0}\" as {1}", str, val));
    else
        Trace.WriteLine(string.Format("Couldn't parse: \"{0}\"", str));
}
Run Code Online (Sandbox Code Playgroud)

那么,是否有一种直接的方法可以不允许接受格式错误的字符串TryParse

更新

感谢所有的建议.

也许我应该澄清:我正在寻找的是前两个字符串是有效的,但第三个被拒绝.

ParseTest("123345.67");
ParseTest("123'456.67");
ParseTest("12'345'6.7");
Run Code Online (Sandbox Code Playgroud)

当然,必须有使用"的方式NumberStyles.AllowThousands",因此它可以选择性地允许千分隔符,但要确保数字格式没有意义?

现在,如果我使用这个:

if (decimal.TryParse(str, styles, CultureInfo.CurrentCulture, out val))
Run Code Online (Sandbox Code Playgroud)

我得到这些结果:

Parsed "123345.67" as 123345.67
Parsed "123'456.67" as 123456.67
Parsed "12'345'6.7" as 123456.7
Run Code Online (Sandbox Code Playgroud)

如果我使用这个:

if (decimal.TryParse(str, styles, CultureInfo.InvariantCulture, out val))
Run Code Online (Sandbox Code Playgroud)

我得到这些结果:

Parsed "123345.67" as 123345.67
Couldn't parse: "123'456.67"
Couldn't parse: "12'345'6.7"
Run Code Online (Sandbox Code Playgroud)

这是我的问题......无论CultureInfo设置如何,都应拒绝第三个字符串,并接受前两个字符串.

Gyö*_*zeg 1

这是因为解析只是跳过NumberFormatInfo.NumberGroupSeparator字符串并完全忽略该NumberFormatInfo.NumberGroupSizes属性。但是,您可以实现这样的验证:

static bool ValidateNumberGroups(string value, CultureInfo culture)
{
    string[] parts = value.Split(new string[] { culture.NumberFormat.NumberGroupSeparator }, StringSplitOptions.None);
    foreach (string part in parts)
    {
        int length = part.Length;
        if (culture.NumberFormat.NumberGroupSizes.Contains(length) == false)
        {
            return false;
        }
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

正如 MSDN所说,它仍然不完全完美:

数组的第一个元素定义紧邻 NumberDecimalSeparator 左侧的最低有效数字组中的元素数量。每个后续元素均指前一组左侧的下一个有效数字组。如果数组的最后一个元素不为 0,则剩余的数字根据数组的最后一个元素进行分组。如果最后一个元素为 0,则剩余数字不分组。

例如,如果数组包含 { 3, 4, 5 },则数字的分组类似于“55,55555,55555,55555,4444,333.00”。如果数组包含 { 3, 4, 0 },则数字的分组类似于“55555555555555555,4444,333.00”。

但你现在可以明白这一点了。