字符串格式货币

65
我在我的Razor视图中有这一行。
@String.Format("{0:C}", @price)

我希望价格前面显示美元符号,但实际上显示的是英镑符号。
我该如何实现这个要求?

5
当你说“pound sign”时,确切指的是什么?是 # 还是 £? - Jon Skeet
7
嗨,Jon,我是你的忠实粉丝。作为英国人,我的意思是英镑符号(£)。 - Sachin Kainth
2
@JonSkeet 非常有趣,从未见过在“井号”方面使用 #,但是快速谷歌搜索可以找到一些很好的信息。 - Tim B James
1
@TimBJames - 这就是我们在美国所称呼的(尽管我现在经常听到它被称为“井号”,就像英国人一直这样做)。 - William
1
@JonSkeet - 你可能还记得我们在TDWTF的时候,它也被称为八角星符号(至少在斜体中是这样)。那里有一个评论者名叫C-Octothorp(来自音乐符号)。 - hoodaticus
8个回答

92

我强烈怀疑问题仅仅是当前处理请求的线程文化设置不当导致。

您可以为整个请求设置文化,或在格式化时指定文化。无论哪种方式,我建议不要使用复合格式的string.Format,除非您确实有多个要格式化的内容(或更宽泛的消息)。而是应该使用:

@price.ToString("C", culture)

这只是让它变得更简单了一些。

编辑:根据你的评论,看起来你可能想要使用英国文化,无论用户使用哪种文化。因此,可以将英国文化设置为整个请求的线程文化,或者可能引入自己的帮助类与一个“常量”:

public static class Cultures
{
    public static readonly CultureInfo UnitedKingdom = 
        CultureInfo.GetCultureInfo("en-GB");
}

那么:

@price.ToString("C", Cultures.UnitedKingdom)

根据我的经验,像这样拥有一个“命名”的文化集合会使使用它的代码更容易阅读,而且您不需要在多个位置正确获取字符串。


3
在获取特定货币符号时硬编码CultureInfo是不可取的。这样做可能无法保证CultureInfo将继续使用您期望的货币符号。但主要问题在于会导致全球化错误,因为会失去适当的区域设置格式(如小数符号、货币符号位置)。请参见我的答案以获取解释。 - Clafou
3
有时候这是抛出婴儿和洗澡水一起丢掉;有时候这是正确的做法。我同意这是一个复杂的话题。在我看来,有一个“货币格式”而不是有一个同时包含金额和货币的“货币”类型,并且可以根据本地文化进行格式化,这是很烦人的。 - Jon Skeet
这可能是一个非常愚蠢的问题,但为什么这个“price”标识符以@开头? - Max Yankov
1
@golergka:仅仅因为在问题中提到了它,并不意味着我足够了解 Razor,可以确定它是否需要 - 它不会在正常的 C# 中使用。 - Jon Skeet
1
@golergka:这只是 Razor 语法告诉我们价格是一个 C# 变量,而不是 HTML 标记。 - MissRaphie
显示剩余3条评论

47

正如其他人所说,您可以通过IFormatProvider来实现这一点。但请记住,货币格式化远远超出了货币符号。

例如,在美国,一个正确格式化的价格可能是"$ 12.50",但在法国,它会被写作"12,50 $"(小数点不同,货币符号的位置也不同)。您不希望仅仅为了更改货币符号而失去这种与文化相适应的格式。

好消息是,您无需这样做,正如以下代码所示:

var cultureInfo = Thread.CurrentThread.CurrentCulture;   // You can also hardcode the culture, e.g. var cultureInfo = new CultureInfo("fr-FR"), but then you lose culture-specific formatting such as decimal point (. or ,) or the position of the currency symbol (before or after)
var numberFormatInfo = (NumberFormatInfo)cultureInfo.NumberFormat.Clone();
numberFormatInfo.CurrencySymbol = "€"; // Replace with "$" or "£" or whatever you need

var price = 12.3m;
var formattedPrice = price.ToString("C", numberFormatInfo); // Output: "€ 12.30" if the CurrentCulture is "en-US", "12,30 €" if the CurrentCulture is "fr-FR".

3
在99%的情况下,这是唯一正确的答案。Jon Skeet可能有更多的粉丝,并且他说CultureInfo/NumberFormatInfo模型不是最优的(至少可以这么说),但在这种情况下,他的答案并不是最合适的。顺便说一句,我最初创建了一个基于当前文化的新CultureInfo对象,仅更改货币符号(因此您也可以这样做),但仅克隆NumberFormatInfo对象肯定更好。 - tne
我已经使用了您的波斯货币解决方案,它有效地排列了我的数字。谢谢。 - Meiki Neumann
这是在各个方面都正确的解决方案。输出格式对用户来说看起来很自然,货币符号也是正确的。 - UltimaWeapon

31

您需要提供一个IFormatProvider:

@String.Format(new CultureInfo("en-US"), "{0:C}", @price)

它位于System.Globalization命名空间中。导入依赖项并使用它。 - Meiki Neumann

14

个人而言,我反对使用特定于文化的代码,建议采用以下方式:

@String.Format(CultureInfo.CurrentCulture, "{0:C}", @price)

同时在您的 web.config 文件中添加以下内容:

<system.web>
    <globalization culture="en-GB" uiCulture="en-US" />
</system.web>

附加信息: https://msdn.microsoft.com/en-us/library/syy068tk(v=vs.90).aspx


5
decimal value = 0.00M;
value = Convert.ToDecimal(12345.12345);
Console.WriteLine(".ToString(\"C\") Formates With Currency $ Sign");
Console.WriteLine(value.ToString("C"));
//OutPut : $12345.12
Console.WriteLine(value.ToString("C1"));
//OutPut : $12345.1
Console.WriteLine(value.ToString("C2"));
//OutPut : $12345.12
Console.WriteLine(value.ToString("C3"));
//OutPut : $12345.123
Console.WriteLine(value.ToString("C4"));
//OutPut : $12345.1234
Console.WriteLine(value.ToString("C5"));
//OutPut : $12345.12345
Console.WriteLine(value.ToString("C6"));
//OutPut : $12345.123450
Console.WriteLine();
Console.WriteLine(".ToString(\"F\") Formates With out Currency Sign");
Console.WriteLine(value.ToString("F"));
//OutPut : 12345.12
Console.WriteLine(value.ToString("F1"));
//OutPut : 12345.1
Console.WriteLine(value.ToString("F2"));
//OutPut : 12345.12
Console.WriteLine(value.ToString("F3"));
//OutPut : 12345.123
Console.WriteLine(value.ToString("F4"));
//OutPut : 12345.1234
Console.WriteLine(value.ToString("F5"));
//OutPut : 12345.12345
Console.WriteLine(value.ToString("F6"));
//OutPut : 12345.123450
Console.Read();

输出控制台屏幕:


1
我建议将答案缩小到问题所问的范围内。虽然这可能是正确的,但只有大约10%的答案与问题有关。此外,我还认为发帖者已经使用了正确的格式,但存在一些区域性问题。因此,这个答案并不是很有帮助。 - Ole Albers

4
针对 Razor,您可以使用以下两个参数:culture 和 value。
@String.Format(new CultureInfo("sv-SE"), @Model.value)

1

使用这个,它很有效而且非常简单:

  var price=22.5m;
  Console.WriteLine(
     "the price: {0}",price.ToString("C", new System.Globalization.CultureInfo("en-US")));

1
对于使用 C# 6.0 字符串插值语法的人:例如:$"The price is {price:C}"文档 提供了几种应用不同 CultureInfo 的方法。
我已经改编了这些示例以使用货币:
decimal price = 12345.67M;
FormattableString message = $"The price is {price:C}";

System.Globalization.CultureInfo.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo("nl-NL");
string messageInCurrentCulture = message.ToString();

var specificCulture = System.Globalization.CultureInfo.GetCultureInfo("en-IN");
string messageInSpecificCulture = message.ToString(specificCulture);

string messageInInvariantCulture = FormattableString.Invariant(message);

Console.WriteLine($"{System.Globalization.CultureInfo.CurrentCulture,-10} {messageInCurrentCulture}");
Console.WriteLine($"{specificCulture,-10} {messageInSpecificCulture}");
Console.WriteLine($"{"Invariant",-10} {messageInInvariantCulture}");
// Expected output is:
// nl-NL      The price is € 12.345,67
// en-IN      The price is ₹ 12,345.67
// Invariant  The price is ¤12,345.67

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接