避免使用小数。TryParse 将“1.1.1”或“1,1,1”识别为十进制
Posted
技术标签:
【中文标题】避免使用小数。TryParse 将“1.1.1”或“1,1,1”识别为十进制【英文标题】:Avoid decimal.TryParse to recognize "1.1.1" or "1,1,1" as decimal 【发布时间】: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
这不是小数点分隔符,NumberGroupSeparator
和 NumberGroupSizes
仅用于输出,小于最大值(默认为 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”怎么办?是一千二十四吗?还是一加分数?
【参考方案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(@"^(\d0,3(,\d3)*(\.\d+)?)$").IsMatch(number))
return decimal.Parse(number, CultureInfo.InvariantCulture);
return new Regex(@"^(\d0,3(\.\d3)*(,\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无法识别:千位分隔符不是强制性的:可能是\d0,+而不是\d0,3
好吧,如果您更新答案以管理像 123456 这样的号码,我将接受作为解决方案以上是关于避免使用小数。TryParse 将“1.1.1”或“1,1,1”识别为十进制的主要内容,如果未能解决你的问题,请参考以下文章