Windows-universal-samples 数字格式化与解析实战:基于 Windows.Globalization.NumberFormatting 的 UWP 全球化指南
示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载本指南以 Samples/NumberFormatting/README.md 为骨架系统讲解 UWP 应用中如何利用Windows.Globalization.NumberFormatting命名空间下的DecimalFormatter、CurrencyFormatter、PercentFormatter、PermilleFormatter、两类NumberRounder与NumeralSystemTranslator实现尊重用户语言与区域偏好的数字显示、解析、舍入、填充与数字系统转换。读完本文你将掌握如何让十进制数、货币、百分比与千分比在不同语言环境下正确呈现并能在不具备数字替换能力的应用中完成拉丁数字到本地数字系统的转换。示例概览Windows.Globalization.NumberFormatting能做什么Windows.Globalization.NumberFormatting命名空间提供一组全球化格式化器它们生成用于显示的字符串时会尊重当前用户的语言与区域偏好或调用方显式指定的语言与区域。命名空间针对十进制数、货币、百分比、千分比per mille即每千分别提供了独立的格式化与解析方法其核心类包括DecimalFormatter十进制数字的格式化与解析CurrencyFormatter货币金额的格式化与解析可指定 ISO 4217 货币代码PercentFormatter百分比的格式化与解析数值 ×100 后附加%符号PermilleFormatter千分比的格式化与解析数值 ×1000 后附加‰符号IncrementNumberRounder/SignificantDigitsNumberRounder按增量或按有效位数舍入RoundingAlgorithm枚举多种舍入算法NumeralSystemTranslator在拉丁数字与其他数字系统之间转换文本。本示例仓库为这一套 API 提供了 7 个可独立运行的场景Scenario每种场景均以 C#cs/、C/CXcpp/与 C/WinRTcppwinrt/三种语言实现UI 布局则共享于 shared/。本文代码示例以 C# 为主同时给出 C/WinRT 的对照方便跨语言迁移。构建与运行示例示例采用标准的 UWP 样例工程组织方式构建与运行步骤如下若以 ZIP 方式下载样例集合务必解压整个压缩包而不仅是包含目标样例的文件夹——因为样例依赖共享的SharedContent目录。启动 Visual Studio选择文件 打开 项目/解决方案。进入解压后的Samples子目录再进入NumberFormatting子目录选择你偏好的语言子目录cs、cpp或cppwinrt双击其中的解决方案文件如 cs/NumberFormatting.sln。按CtrlShiftB或选择生成 生成解决方案编译。运行与部署方式仅部署选择生成 部署解决方案部署并运行按F5调试 开始调试进入调试运行或按CtrlF5调试 开始执行不调试直接运行。环境前提本示例需要 Windows 10 才能执行并依赖 Visual Studio 进行构建。在 Package.appxmanifest 中可以查看示例声明的功能与最低目标版本。场景 1百分比与千分比格式化对应源码cs/Scenario1_PercentPermilleFormatting.xaml.cs本场景演示PercentFormatter与PermilleFormatter的典型用法覆盖默认偏好、指定语言、分组、小数位与强制小数点的控制// 构造默认跟随当前用户偏好的格式化器 PercentFormatter defaultPercentFormatter new PercentFormatter(); // 使用语言列表与区域构造法语fr-FR、阿拉伯语arZZ 表示不指定区域 PercentFormatter frPercentFormatter new PercentFormatter(new[] { fr-FR }, ZZ); PercentFormatter arPercentFormatter new PercentFormatter(new[] { ar }, ZZ); PermilleFormatter defaultPermilleFormatter new PermilleFormatter(); PermilleFormatter arPermilleFormatter new PermilleFormatter(new[] { ar }, ZZ); double randomNumber new Random().NextDouble(); ulong fixedNumber 500; // 分组显示千位分隔符 defaultPercentFormatter.IsGrouped true; results.AppendLine(Percent formatted (grouped): defaultPercentFormatter.Format(fixedNumber)); // 不显示小数位 defaultPercentFormatter.FractionDigits 0; defaultPercentFormatter.IsGrouped false; // 始终显示小数点即使没有小数部分 defaultPercentFormatter.IsDecimalPointAlwaysDisplayed true;关键点IsGrouped控制是否使用千位分组分隔符不同语言的分隔符与分组习惯不同如 fr-FR 使用空格/窄空格而非逗号FractionDigits小数位数置 0 时不显示小数部分IsDecimalPointAlwaysDisplayed强制始终显示小数点常用于对账、精确展示等场景阿拉伯语ar构造出的格式化器会自动执行数字替换详见场景 6输出东方阿拉伯数字字形。场景 2十进制数字格式化对应源码cs/Scenario2_DecimalFormatting.xaml.csDecimalFormatter是通用性最强的格式化器。本场景演示默认偏好、分组、指定语言与小数位控制的组合// 使用当前用户偏好初始化 DecimalFormatter decimalFormat new DecimalFormatter(); double randomNumber new Random().NextDouble() * 100000; // 开启分组 DecimalFormatter decimalFormat1 new DecimalFormatter(); decimalFormat1.IsGrouped true; // 法语分组 DecimalFormatter decimalFormatFR new DecimalFormatter(new string[] { fr-FR }, ZZ); decimalFormatFR.IsGrouped true; // 阿拉伯语自动数字替换 DecimalFormatter decimalFormatAR new DecimalFormatter(new string[] { ar }, ZZ); decimalFormatAR.IsGrouped true; ulong fixedNumber 500; // 无小数位但始终显示小数点 → 500. DecimalFormatter decimalFormat3 new DecimalFormatter(); decimalFormat3.IsDecimalPointAlwaysDisplayed true; decimalFormat3.FractionDigits 0; // 无小数位也不显示小数点 → 500 DecimalFormatter decimalFormat4 new DecimalFormatter(); decimalFormat4.FractionDigits 0;值得注意的对比是decimalFormat3与decimalFormat4两者都设置FractionDigits 0差别仅在IsDecimalPointAlwaysDisplayed——前者输出带小数点如500.后者输出纯整数如500。这展示了IsDecimalPointAlwaysDisplayed的语义它只控制是否显示小数点符号与是否显示小数数字相互独立。场景 3货币格式化对应源码cs/Scenario3_CurrencyFormatting.xaml.cs 与 cppwinrt/Scenario3_CurrencyFormatting.cpp货币格式化的核心是CurrencyFormatter它的构造参数是ISO 4217 货币代码如USD、EUR、JPY并可叠加语言列表与区域。示例展示了从用户默认货币到多语言欧元格式化的完整路径using Windows.System.UserProfile; // 取当前用户的默认货币ISO 4217 代码 string currency GlobalizationPreferences.Currencies[0]; CurrencyFormatter defaultCurrencyFormatter new CurrencyFormatter(currency); // 固定货币 默认数字格式 CurrencyFormatter usdCurrencyFormatter new CurrencyFormatter(CurrencyIdentifiers.USD); // 欧元但使用法国fr-FR与爱尔兰gd-IE的本地数字格式 CurrencyFormatter eurFRCurrencyFormatter new CurrencyFormatter(CurrencyIdentifiers.EUR, new[] { fr-FR }, FR); CurrencyFormatter eurIECurrencyFormatter new CurrencyFormatter(CurrencyIdentifiers.EUR, new[] { gd-IE }, IE); // 小数位与分组 usdCurrencyFormatter.FractionDigits 2; usdCurrencyFormatter.IsGrouped true; // 用货币代码替代货币符号 CurrencyFormatter currencyFormatEuroModeSwitch new CurrencyFormatter(CurrencyIdentifiers.EUR); currencyFormatEuroModeSwitch.Mode CurrencyFormatterMode.UseCurrencyCode; // 输出 12345.67 EUR currencyFormatEuroModeSwitch.Mode CurrencyFormatterMode.UseSymbol; // 输出 €12345.67CurrencyFormatterMode枚举控制金额的呈现模式UseSymbol默认使用€、$等货币符号、UseCurrencyCode使用EUR、USD等 ISO 4217 代码。同一格式化器可在两种模式间动态切换。C/WinRT 版本的写法在 API 形态上完全对应属性改为函数调用风格例如CurrencyFormatter currencyFormatUSD(CurrencyIdentifiers::USD()); currencyFormatUSD.FractionDigits(2); currencyFormatUSD.IsGrouped(true); currencyFormatEuroModeSwitch.Mode(CurrencyFormatterMode::UseCurrencyCode);C/WinRT 版本完整实现见 cppwinrt/Scenario3_CurrencyFormatting.cppC/CX 版本位于 cpp/Scenario3_CurrencyFormatting.xaml.cpp。场景 4数字解析Format → Parse 往返对应源码cs/Scenario4_NumberParsing.xaml.cs格式化器的反向能力是解析ParseDouble(string)将按同一语言/区域规则生成的字符串还原为数值。本场景对百分比、十进制、货币三种格式化器分别做格式化→解析往返roundtrip验证// 百分比0.523 → 52.30% → 0.523 PercentFormatter percentFormat new PercentFormatter(); string percent1 percentFormat.Format(0.523); double percent1Parsed percentFormat.ParseDouble(percent1).Value; // 十进制开启分组 DecimalFormatter decimalFormat new DecimalFormatter(); decimalFormat.IsGrouped true; string decimal1 decimalFormat.Format(12345.67); double decimal1Parsed decimalFormat.ParseDouble(decimal1).Value; // 货币 CurrencyFormatter currencyFormat new CurrencyFormatter(GlobalizationPreferences.Currencies[0]); string currency1 currencyFormat.Format(1234.56); double currency1Parsed currencyFormat.ParseDouble(currency1).Value;场景还验证了跨语言的往返一致性为ja日语与fr-FR法语分别构造同一类别的格式化器格式化与解析均使用同一格式化器实例从而保证往返结果与输入一致。ParseDouble返回可空值double?当输入字符串不符合该格式化器的语言/区域规则时返回null代码中以.Value访问前应做空值判断。场景 5舍入Rounding与填充Padding对应源码cs/Scenario5_RoundingAndPadding.xaml.csUI 见 shared/Scenario5_RoundingAndPadding.xaml这是本示例中技术密度最高的场景演示了RoundingAlgorithm的全部 11 种取值、两类NumberRounder以及位数填充属性。RoundingAlgorithm枚举包括枚举值行为None不执行舍入RoundUp/RoundDown无条件向远离零 / 向零方向进位或舍去RoundTowardsZero/RoundAwayFromZero向零 / 远离零取整RoundHalfUp/RoundHalfDown恰好一半时进位 / 舍去RoundHalfTowardsZero/RoundHalfAwayFromZero恰好一半时向零 / 远离零RoundHalfToEven/RoundHalfToOdd恰好一半时取偶数 / 取奇数银行家舍入场景以DisplayRoundingAlgorithmAsString辅助方法源码第 3176 行将这些枚举值映射为可读文本便于在输出中展示。两类舍入器IncrementNumberRounder——按增量舍入Increment属性指定步长示例遍历0.001、0.01、0.1、1.0IncrementNumberRounder rounder new IncrementNumberRounder(); rounder.RoundingAlgorithm RoundingAlgorithm.RoundHalfUp; rounder.Increment 0.01; // 以 0.01 为步长 // 将 rounder 挂到格式化器上避免直接展示时的精度问题 DecimalFormatter formatter new DecimalFormatter(); formatter.NumberRounder rounder; string formatted formatter.Format(0.1458); // 0.15源码注释特别提示建议将增量舍入器挂接到格式化器内使用formatter.NumberRounder rounder以避免直接展示舍入结果时的浮点精度问题。SignificantDigitsNumberRounder——按有效位数舍入SignificantDigits指定位数示例遍历3、2、1SignificantDigitsNumberRounder rounder new SignificantDigitsNumberRounder(); rounder.RoundingAlgorithm RoundingAlgorithm.RoundUp; rounder.SignificantDigits 3; double rounded rounder.RoundDouble(0.1458); // 0.146该舍入器也可直接调用RoundDouble/RoundInt32/RoundUInt64等方法独立使用。位数填充Padding格式化器上的SignificantDigits、IntegerDigits、FractionDigits属性共同决定输出的宽度IntegerDigits是最少整数位数不足补零FractionDigits是最少小数位数不足补零。例如对0.12、1.2、10.2、102四组数值仅设置SignificantDigits 4、IntegerDigits 0、FractionDigits 0时输出体现有效位数的填充行为对PercentFormatter设置SignificantDigits 4、IntegerDigits 2、FractionDigits 2可同时看到有效位数与最小整数/小数位数的联合效果。DoPaddingScenarios源码第 85105 行通过ISignificantDigitsOption与INumberFormatterOptions接口读取这些属性说明四类格式化器Decimal/Percent/Permille/Currency共享同一组填充选项。货币专用舍入ApplyRoundingForCurrency对于货币示例推荐使用CurrencyFormatter.ApplyRoundingForCurrency(roundingAlgorithm)方法它会依据该货币与语言对应的小数位规则自动创建一个合适增量的IncrementNumberRounder并挂接比手动设置NumberRounder更贴合货币业务。场景分别对日元JPY使用RoundHalfToOdd与欧元EUR使用RoundHalfToEven演示。场景 6数字系统转换NumeralSystemTranslator对应源码cs/Scenario6_NumeralSystemTranslation.xaml.cs许多应用在渲染文本时并不具备数字替换能力例如富文本控件中的部分内容NumeralSystemTranslator用于把拉丁数字翻译成任意受支持的数字系统字形然后再交给渲染层。注意转换仅发生在拉丁数字系统与其他数字系统之间两个非拉丁系统之间的互译不在支持范围内源码第 3738 行注释明确说明。string stringToTranslate These are the 10 digits of a numeral system: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9; // 基于当前应用语言初始化如 zh-Hans-CN 对应 latn 拉丁数字 NumeralSystemTranslator numeralTranslator new NumeralSystemTranslator(); results.Append(numeralTranslator.TranslateNumerals(stringToTranslate)); // 通过属性切换数字系统如 hanidec中文十进制数字 〇一二三四… numeralTranslator.NumeralSystem hanidec; results.Append(numeralTranslator.TranslateNumerals(stringToTranslate)); // 通过语言列表初始化ar-SA 会解析出适合的东方阿拉伯数字系统 numeralTranslator new NumeralSystemTranslator(new string[] { ar-SA, en-US }); results.Append(numeralTranslator.TranslateNumerals(stringToTranslate));NumeralSystem属性接受 BCP 47 数字系统扩展中定义的标准标识符如latn、arab、hanidec等若通过语言列表构造翻译器会从语言列表中解析出相应的默认数字系统。场景 7使用带 Unicode 扩展的语言标签对应源码cs/Scenario7_UsingUnicodeExtensions.xaml.csBCP 47 语言标签支持-u-开头的 Unicode 扩展其中nunumbering system扩展可以直接驱动格式化器与翻译器的数字系统。本场景在语言列表中注入扩展一次性构造全部四类格式化器与NumeralSystemTranslator// de-DE-u-nu-telu德语的泰卢固语数字系统ja-jp-u-nu-arab日语的阿拉伯数字系统 string[] languages new[] { de-DE-u-nu-telu-ca-buddist-co-phonebk-cu-usd, ja-jp-u-nu-arab }; IncrementNumberRounder rounder new IncrementNumberRounder(); rounder.Increment 0.001; DecimalFormatter decimalFormatter new DecimalFormatter(languages, ZZ); decimalFormatter.NumberRounder rounder; decimalFormatter.FractionDigits 2; CurrencyFormatter currencyFormatter new CurrencyFormatter(CurrencyIdentifiers.EUR, languages, ZZ); currencyFormatter.NumberRounder rounder; currencyFormatter.FractionDigits 2; PercentFormatter percentFormatter new PercentFormatter(languages, ZZ); percentFormatter.NumberRounder rounder; percentFormatter.FractionDigits 2; PermilleFormatter permilleFormatter new PermilleFormatter(languages, ZZ); permilleFormatter.NumberRounder rounder; permilleFormatter.FractionDigits 2; NumeralSystemTranslator numeralTranslator new NumeralSystemTranslator(languages);示例输出中特意打印decimalFormatter.ResolvedLanguage并附注释除nu之外的所有扩展标签如ca日历、co排序、cu货币在数字格式化解析时均被忽略——只有nu会影响数字格式化行为。这一场景说明你可以复用一份带完整扩展的语言标签例如同时包含日历、排序、货币偏好而格式化器只取其中与数字相关的nu段。多语言实现对照与工程结构示例在三种语言下保持 1:1 的场景对应关系C#cs/ 下每个ScenarioN_*.xaml.cs对应一个场景C/WinRTcppwinrt/ 下以.cpp/.h形式实现并通过 Project.idl 声明页面类型属性访问为函数调用风格如Formatter.FractionDigits(2)C/CXcpp/ 下为.xaml.cpp/.xaml.h形式。三份 UI 布局集中在 shared/每个场景页面均包含场景描述、Display按钮与OutputTextBlock输出区因此切换语言实现时界面行为完全一致。相关示例与进一步探索Windows.Globalization.NumberFormatting是 UWP 全球化与本地化能力的一部分建议与本仓库中以下相关样例配合阅读Calendar 示例日历的全球化格式化与解析DateTimeFormatting 示例日期时间的全球化格式化GlobalizationPreferences 示例读取用户语言、区域、货币等全球化偏好archived/NumberFormatting/本示例的 JavaScript 归档版本可对照查看同一主题在 JS 平台上的历史实现。实践建议在真实应用中若同时涉及数字、货币、日期与日历的本地化展示应统一从GlobalizationPreferences读取用户偏好如GlobalizationPreferences.Currencies[0]并将其作为格式化器的初始化依据对于需要精确控制输出宽度的场景如表格、票据优先组合使用IntegerDigits、FractionDigits、SignificantDigits与合适的RoundingAlgorithm并牢记将舍入器挂接进格式化器以规避浮点精度问题。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐UWP 中 Windows Runtime XML API 实战指南基于 Windows-universal-samples 的 XmlDocument 样例UWP 中 Windows Runtime XML API 实战指南基于 Windows universal samples 的 XmlDocument 样例示例工程UWP 中 ListView 与 GridView 的实战指南基于 Windows-universal-samples XamlListView 示例的源码解析UWP 中 ListView 与 GridView 的实战指南基于 Windows universal samples XamlListView 示例的源码解示例工程SleeperXmacOS系统级电源管理框架的技术实现与应用SleeperXmacOS系统级电源管理框架的技术实现与应用 在macOS生态系统中电源管理一直是一个复杂而关键的技术领域。对于需要在特定场景下保持系统活跃示例工程上一篇agent-plugins GitHub Actions3个配方快速打造技能质量CI门禁下一篇如何永久保存微信聊天记录WeChatMsg完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考