【问题标题】:Avoid decimal.TryParse to recognize "1.1.1" or "1,1,1" as decimal避免使用小数。TryParse 将“1.1.1”或“1,1,1”识别为十进制
【发布时间】:2016-03-07 09:27:39
【问题描述】:

我在字符串识别方面遇到问题:我试图只识别正确格式的数字,但不知道如何。

我正在编写一种文化不变的方式,因此我需要识别“,”和“。”作为小数和千位分隔符,反之亦然。

所有这些对我来说都是正确的格式:

12,1
12.1
1.000,12
1,000.12

但是这样的事情是错误的

1.2.3
1,2,3

我试过了:

NumberStyles style;
decimal n;  
object valore;                                  
style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign | NumberStyles.AllowThousands;

Console.WriteLine(decimal.TryParse(valore.ToString(), style , CultureInfo.InvariantCulture, out n));

this is the fiddle to test it

但是“1,1,1”被读取为有效数字,而“1.1.1”则不是。

如果我使用我的特定文化(“it-IT”),“1,1,1”会被识别,而“1.1.1”则不会。

如何丢弃所有无效字符串?

【问题讨论】:

  • 据我所知,您没有在代码中的任何地方使用style
  • 这不是小数点分隔符,NumberGroupSeparatorNumberGroupSizes 仅用于输出,小于最大值(默认为 3)是允许的。
  • 所有这些对我来说都是正确的格式。不,他们不是。您不知道该值是 1000.12 还是 100012。相差 100 倍从来都不是很微妙。所以这对于其他字符串也会出错,比如 1,1,1。您认为您可以正确执行此操作的假设是不正确的。
  • @gt.guybrush 标准 .NET 格式化和解析基础结构并非旨在处理此类情况。但是无论你是让它按照你想要的那样工作,还是制作你自己的解析器,你仍然会遇到一个问题——歧义。您将如何处理字符串“My numbers are 1,000 1,001 1.000 1.001”(英语)和“Meine Zahlen sind 1,000 1,001 1.000 1.001”(德语)?相同的字符串表示将意味着完全不同的事情,因此几乎不可能做到。一些智能文本分析可能会识别语言/文化,但即使这样也不可靠。
  • 允许两种数字格式会引发更大的问题:如果您收到输入字符串“1.024”怎么办?是一千二十四吗?还是一加分数?

标签: c# type-conversion number-formatting tryparse


【解决方案1】:

我用个人解析器结束了这个,我希望找到一个更好的解决方案,但是读取 cmets 似乎不太可能

public static bool tryValoreNumerico(object valore, out decimal valoreRestituito)
    {
        decimal n;          
        string testoNormalizzato;

        valoreRestituito = 0;

        // normalizzazione
        if (valore.ToString().Contains(",") && valore.ToString().Contains("."))
        {
            if (valore.ToString().IndexOf(".") < valore.ToString().IndexOf(","))
            {
                testoNormalizzato = valore.ToString().Replace(".", "");
            }
            else
            {
                testoNormalizzato = valore.ToString().Replace(",", "");
            }
        }
        else
        {
            if ((valore.ToString().Length - valore.ToString().Replace(",", "").Length) > 1)
            {
                string[] pezzi = valore.ToString().Split(',');
                for (int i = 1; i < pezzi.Length; i++ )
                {
                    if (pezzi[i].Length != 3)
                        return false;
                }

                testoNormalizzato = valore.ToString().Replace(",", "");
            }
            else if ((valore.ToString().Length - valore.ToString().Replace(".", "").Length) > 1)
            {
                string[] pezzi = valore.ToString().Split('.');
                for (int i = 1; i < pezzi.Length; i++)
                {
                    if (pezzi[i].Length != 3)
                        return false;
                }

                testoNormalizzato = valore.ToString().Replace(".", "");
            }

            else
                testoNormalizzato = valore.ToString();

        }
        testoNormalizzato = testoNormalizzato.Replace(",", ".");

        if (decimal.TryParse(testoNormalizzato, out n) && testoNormalizzato == Convert.ToDecimal(testoNormalizzato, new CultureInfo("en-US")).ToString().Replace(",", "."))
        {
            valoreRestituito = Convert.ToDecimal(testoNormalizzato, new CultureInfo("en-US"));
        }
        return decimal.TryParse(testoNormalizzato, out n) && testoNormalizzato == Convert.ToDecimal(testoNormalizzato, new CultureInfo("en-US")).ToString().Replace(",", ".");

    }

首先我将数字标准化为 EN 格式,然后尝试转换它

最后的测试是看没有与数字“相似”的文本,因为像“001”、“100 01”这样的字符串不是数字。

比率是:每个字符串都必须保持不变:“001”转换为数字变为“1”,与原始值不同,因此必须避免这种转换

this is the fiddle

【讨论】:

    【解决方案2】:

    我建议您使用Regex 进行验证和这样的自定义解析方法:

    public static decimal DecimalParse(string number)
    {
        if (new Regex(@"^\d+$").IsMatch(number))
        {
            return decimal.Parse(number, CultureInfo.InvariantCulture);
        }
        if (new Regex(@"^(\d{0,3}(,\d{3})*(\.\d+)?)$").IsMatch(number))
        {
            return decimal.Parse(number, CultureInfo.InvariantCulture);
        }
        return new Regex(@"^(\d{0,3}(\.\d{3})*(,\d+)?)$").IsMatch(number)
            ? decimal.Parse(number.Replace(".", "").Replace(",", "."), CultureInfo.InvariantCulture)
            : 0;
    }
    

    结果将是:

    string num;
    num = "1,000";      Console.WriteLine("{0}", DecimalParse(num));     //1000
    num = ",01";        Console.WriteLine("{0}", DecimalParse(num));     //0.01
    num = ".02";        Console.WriteLine("{0}", DecimalParse(num));     //0.02
    num = "12,1";       Console.WriteLine("{0}", DecimalParse(num));     //12.1
    num = "12.1";       Console.WriteLine("{0}", DecimalParse(num));     //12.1
    num = "1.000,12";   Console.WriteLine("{0}", DecimalParse(num));     //1000.12
    num = "1.000.000,12"; Console.WriteLine("{0}", DecimalParse(num));   //1000000.12
    num = "1,000.12";   Console.WriteLine("{0}", DecimalParse(num));     //1000.12
    num = "1,000,000.12"; Console.WriteLine("{0}", DecimalParse(num));   //1000000.12
    num = "1000";       Console.WriteLine("{0}", DecimalParse(num));     //0
    num = "110.";       Console.WriteLine("{0}", DecimalParse(num));     //0
    num = "110,";       Console.WriteLine("{0}", DecimalParse(num));     //0
    num = "1.2.3";      Console.WriteLine("{0}", DecimalParse(num));     //0
    num = "1,2,3";      Console.WriteLine("{0}", DecimalParse(num));     //0
    

    【讨论】:

    • 无法让它在我的具有意大利文化的机器上工作:第一个正则表达式通过但 decimal.parge thow 错误。你能制作一个与文化无关的版本吗?
    • return decimal.Parse(number, CultureInfo.InvariantCulture); 也有错误吗?
    • 所以,我使用CultureInfo.InvariantCulture 更新了我的答案; 1,2 应该返回 1.2 ;)。
    • 其他情况:1234无法识别:千位分隔符不是强制性的:可能是\d{0,+}而不是\d{0,3}
    • 好吧,如果您更新答案以管理像 123456 这样的号码,我将接受作为解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 2021-07-23
    相关资源
    最近更新 更多