C# 跨区域十进制/双解析
事实上,我有多个系统可以生成数字数据,它们以文本文件的形式存储在某个web服务器上。有些系统使用小数点作为分数分隔符,有些系统使用小数逗号作为分隔符 应用程序(胖客户端,.NET2.0)也可以在任何一种系统上运行 所以在经历了一些绊脚石之后,我做了这个:() 你能推荐更好、更优雅的方式吗 编辑:C# 跨区域十进制/双解析,c#,parsing,regional-settings,C#,Parsing,Regional Settings,事实上,我有多个系统可以生成数字数据,它们以文本文件的形式存储在某个web服务器上。有些系统使用小数点作为分数分隔符,有些系统使用小数逗号作为分隔符 应用程序(胖客户端,.NET2.0)也可以在任何一种系统上运行 所以在经历了一些绊脚石之后,我做了这个:() 你能推荐更好、更优雅的方式吗 编辑: 很抱歉,我之前没有提到这一点,因为您的答案倾向于这个方向-我无法用数字存储生成区域性,我只能尝试“检测”它。如果您无法更改呼叫站点,并且您保证小数点分隔符旁边不会出现其他类型的分隔符,那么您可以,或多或
很抱歉,我之前没有提到这一点,因为您的答案倾向于这个方向-我无法用数字存储生成区域性,我只能尝试“检测”它。如果您无法更改呼叫站点,并且您保证小数点分隔符旁边不会出现其他类型的分隔符,那么您可以,或多或少地使用你的方法。我建议
HasDecimalComma
和HasDecimalPeriod
提供给方法体-全局状态TryParse
而不是Parse
,因为这些数字可能有错误不变量区域性
区域性(它有一个小数点)///comment the method assumptions here
///otherwise the method might seem wrong
public static double GetNumber(string numberString)
{
bool hasDecimalComma = numberString.Contains(',');
if (hasDecimalComma)
numberString = numberString.Replace(',', '.')
double result;
bool success = double.TryParse(numberString,
NumberStyles.Float,
CultureInfo.InvariantCulture,
out result);
if (success)
return result;
else
throw new ArgumentException(
string.Format("can't parse '{0}'", numberString));
}
(旧答案,原则上很好,实际上不可能) 我建议沿字符串存储生成的区域性,然后使用它调用方法,沿以下行(使用): 试试这个:
static double GetDouble(string s)
{
double d;
var formatinfo = new NumberFormatInfo();
formatinfo.NumberDecimalSeparator = ".";
if (double.TryParse(s, NumberStyles.Float, formatinfo, out d))
{
return d;
}
formatinfo.NumberDecimalSeparator = ",";
if (double.TryParse(s, NumberStyles.Float, formatinfo, out d))
{
return d;
}
throw new SystemException(string.Format("strange number format '{0}'", s));
}
只需使用当前区域性和正确的数字格式标志。当然,您必须针对数据库中可能存储的所有区域性进行测试。更好的方法是:在将数字存储到数据库之前,将其转换为CultureInfo.不变的区域性。或:存储号码时还存储区域性标识符
using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
const string toTest = "1.006,30";
float number;
if (float.TryParse(toTest, NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.CurrentCulture, out number))
Console.WriteLine("Success: {0}", number);
else
Console.WriteLine("Failure: strange number format");
Console.WriteLine("Press any key to finish");
Console.ReadKey();
}
}
}
除非您的一些客户使用波斯语(
fa
,fa-IR
标记)作为他们的文化,否则我认为您可以:
// apparently, Persians use '/' as the decimal separator
var slash = CultureInfo
.GetCultures(CultureTypes.AllCultures)
.Where(c =>
c.NumberFormat.NumberDecimalSeparator != "," &&
c.NumberFormat.NumberDecimalSeparator != ".")
.ToList();
您能用数字字符串存储生成的区域性吗?这将减少对这种字符串弯曲的需求。你知道生成的数字大致是多少吗?例如,一组选项?我不确定您的系统将如何处理解析“1000.12”(实际上我知道,它会崩溃)。如果可能的格式数量有限,那么如果没有歧义的可能,您可以尝试每种格式。我很幸运,因此永远不会出现千位分隔符。因此,您可以保证您的数字是一个可能带前导减号的数字字符串,并且可以是“.”,a“,”或者字符串中的某个地方都没有?总是,总是,总是使用不变区域性序列化浮点。持久化日期应始终为已知形式。如果不是,你就失败了。如果将
用作千位分隔符,这可能不起作用。显然,这不是一个问题,正如在评论(问题)中所阐明的那样,因此这看起来不错。根据这一点更改了答案。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
const string toTest = "1.006,30";
float number;
if (float.TryParse(toTest, NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.CurrentCulture, out number))
Console.WriteLine("Success: {0}", number);
else
Console.WriteLine("Failure: strange number format");
Console.WriteLine("Press any key to finish");
Console.ReadKey();
}
}
}
// apparently, Persians use '/' as the decimal separator
var slash = CultureInfo
.GetCultures(CultureTypes.AllCultures)
.Where(c =>
c.NumberFormat.NumberDecimalSeparator != "," &&
c.NumberFormat.NumberDecimalSeparator != ".")
.ToList();