如何在 C# 中更改 NaN 字符串表示?

Posted

技术标签:

【中文标题】如何在 C# 中更改 NaN 字符串表示?【英文标题】:How to change NaN string representation in C#? 【发布时间】:2013-02-24 10:00:23 【问题描述】:

我的程序将点云保存到文件中,其中每个点云都是来自System.Windows.Media.Media3D 命名空间的Point3D[,]。这显示了输出文件的一行(葡萄牙语):

-112,644088741971;71,796623005014;NaN (Não é um número)

虽然我希望它是(为了之后正确解析):

-112,644088741971;71,796623005014;NaN

生成文件的代码块在这里:

var lines = new List<string>();

for (int rows = 0; rows < malha.GetLength(0); rows++) 
    for (int cols = 0; cols < malha.GetLength(1); cols++) 

        double x = coordenadas_x[cols];
        double y = coordenadas_y[rows];
        double z;

        if ( SomeTest() ) 
            z = alglib.rbfcalc2(model, x, y);
         else 
            z = double.NaN;
        

        var p = new Point3D(x, y, z);
        lines.Add(p.ToString());                       

        malha[rows, cols] = p;
    


File.WriteAllLines("../../../../dummydata/malha.txt", lines);

似乎从Point3D.ToString() 内部调用的double.NaN.ToString() 方法包括我根本不想要的括号中的“附加解释”。

有没有办法改变/覆盖这个方法,使它只输出NaN,不带括号部分?

【问题讨论】:

看看 NumberFormatInfo.NaNSymbol(msdn.microsoft.com/en-us/library/0c899ak8.aspx 的注释部分) @daniloquio 你认为你可以提供一个快速的工作代码和你的建议吗?我很确定我在找什么! 用解决方案编辑了我当前的答案。请看一下 【参考方案1】:

Double.ToString() 使用NumberFormatInfo.CurrentInfo 来格式化其数字。最后一个属性引用当前在活动线程上设置的CultureInfo。这默认为用户的当前语言环境。在这种情况下,它是葡萄牙文化环境。要避免这种行为,请使用Double.ToString(IFormatProvider) 重载。在这种情况下,您可以使用CultureInfo.InvariantCulture

此外,如果您想保留所有其他标记,您可以只切换 NaN 符号。默认情况下,全球化信息是只读的。创建一个克隆将解决这个问题。

System.Globalization.NumberFormatInfo numberFormatInfo = 
    (System.Globalization.NumberFormatInfo) System.Globalization.NumberFormatInfo.CurrentInfo.Clone();
numberFormatInfo.NaNSymbol = "NaN";

double num = double.NaN;
string numString = System.Number.FormatDouble(num, null, numberFormatInfo);

要在当前线程上设置此项,请创建当前文化的副本并在文化上设置数字格式信息。 Pre .NET 4.5 无法为所有线程设置它。创建每个线程后,您必须确保正确的CultureInfo。从 .NET 4.5 开始,CultureInfo.DefaultThreadCurrentCulture 定义了 AppDomain 中线程的默认区域性。仅当尚未设置线程的文化时才考虑此设置(请参阅 MSDN)。

单线程示例:

System.Globalization.CultureInfo myCulture =
     (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
myCulture.NumberFormat.NaNSymbol = "NaN";

System.Threading.Thread.CurrentThread.CurrentCulture = myCulture;   
string numString = double.NaN.ToString();

【讨论】:

这不会产生他想要的输出,它使用本地化的小数分隔符。 目前我得到了字符串NaN (não é um número)。我的目标不是获得NaN (not a number),而是获得普通的NaN。我怎么能得到这个? @heltonbiker:您想为整个程序全局更改此设置,还是仅在此循环内格式化Point3D 我将采用文化换当前线程的方法,但为了记录,我测试了output.Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NaNSymbol, "NaN"),它运行良好。一个很好的快速和肮脏的技巧! +1 对实现进行了一些小的修正。我测试了它,我可以说它就像一个魅力。【参考方案2】:

不要将 NaN 值传递给 ToString

例如(包装在扩展方法中以便于重用):

static string ToCleanString(this double val)

    if (double.IsNan(val)) return "NaN";
    return val.ToString();

【讨论】:

我更新了我的代码。实际上 double.NaN.ToString() 方法是从 Point3D.ToString() 方法内部调用的... @heltonbiker:是的,我想知道这一点。它改变了一切。我认为我的偏好只是用我自己的方法替换 Point3D.ToString() 调用,该方法在我的控制下转换和连接所有三个值。【参考方案3】:

怎么样:

NumberFormatInfo myFormatInfo = NumberFormatInfo.InvariantInfo;

Point3D myPoint = new Point3D(1,1,double.NaN);
var pointString = myPoint.ToString(myFormatInfo);

【讨论】:

【参考方案4】:

首先,Caramiriel 提供的答案是让double.NaN 由您可能想要的任何字符串表示。

顺便说一句,我想要字符串"NaN",下面是the docs 对NumberFormatInfo.NaNSymbol 的评价:

表示 IEEE NaN(不是数字)值的字符串。 InvariantInfo 的默认值为“NaN”。

然后我想出了如何使用InvariantCultureInfo 提供的默认值来获得我想要的纯“NaN”字符串并去掉逗号分隔符,在创建当前线程之后添加以下行:

Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;

效果很好!

【讨论】:

以上是关于如何在 C# 中更改 NaN 字符串表示?的主要内容,如果未能解决你的问题,请参考以下文章

如何在c#中更改数据表中所有列的数据类型[重复]

如何在 Nodejs 调试控制台视图中更改对象的字符串表示

如何在 Node.js 中解析包含“NaN”的 JSON 字符串

系统函数的应用

C#中的“定义字符串变量”是啥意思。

从外部更改应用程序字符串c#