C++ money_get<> facet解析欧元金额异常问题求助
解决C++ money_get facet解析欧元金额时的符号位置问题
我刚梳理了你的测试情况,这确实是个容易踩的locale格式匹配坑,先帮你理清楚问题根源,再给出可行的解决办法:
问题出在哪?
从你给出的de_DE.utf8 locale的money_punct配置能明确看到:
pos_format: sign value space symbol
这个规则意味着合法的正向欧元金额格式是「数值 + 空格 + 货币符号」,比如456789,12 €。但你测试字符串里写的是€ 456789,12 €——把货币符号放在了数值前面,完全不符合locale预期的格式顺序,所以money_get解析到€时直接判定格式错误,停止了解析,这就是第四个金额没被读出来的原因。
而USD测试能正常运行,是因为en_US.UTF-8的money_punct规则里,货币符号就是放在数值前面的(比如$1.11),和你的输入格式完美匹配,所以没出问题。
两种解决方案
1. 调整输入格式匹配locale默认规则
最简单的方式是把欧元金额改成「数值 + 空格 + €」的形式,比如把测试字符串修改为:
std::string str = "1,11 2,22 3,33 456789,12 €";
这样get_money就能顺利解析所有金额了。
2. 自定义money_punct facet修改格式规则
如果没法调整输入格式,你可以自定义一个money_punct facet,把金额格式改成「货币符号在前」,再注入到locale中使用。示例代码如下:
#include <iostream> #include <sstream> #include <locale> #include <iomanip> // 自定义适配符号前置的欧元格式facet class EuroMoneyPunct : public std::money_punct<char> { protected: // 修改正向金额格式:符号(可选)+ 货币符号 + 空格 + 数值 pattern do_pos_format() const override { return { {symbol, space, value, none} }; } // 负向金额格式同理调整 pattern do_neg_format() const override { return { {symbol, space, value, sign} }; } // 其他规则保持和de_DE.utf8一致 char do_decimal_point() const override { return ','; } char do_thousands_sep() const override { return '.'; } std::string do_grouping() const override { return "\3\3"; } std::string do_curr_symbol() const override { return "€"; } int do_frac_digits() const override { return 2; } std::string do_positive_sign() const override { return ""; } std::string do_negative_sign() const override { return "-"; } }; int main() { std::string str = "1,11 2,22 3,33 € 456789,12 €"; std::istringstream s1(str); // 创建自定义locale:基于de_DE.utf8,替换money_punct facet std::locale custom_locale(std::locale("de_DE.utf8"), new EuroMoneyPunct); s1.imbue(custom_locale); std::cout << std::fixed << std::setprecision(2); std::cout << '"' << str << "\" parsed with the I/O manipulator: "; long double val; while(s1 >> std::get_money(val)) { std::cout << val/100 << ' '; } std::cout << '\n'; // 直接使用facet的测试也适配这个自定义locale std::string str2 = "€ 1.234,56 EUR"; std::istringstream s2(str2); s2.imbue(custom_locale); std::cout << '"' << str2 << "\" parsed with the facet directly: "; auto& f = std::use_facet<std::money_get<char>>(s2.getloc()); std::ios_base::iostate err; std::istreambuf_iterator<char> beg(s2), end; f.get(beg, end, true, s2, err, val); std::cout << val/100 << '\n'; }
这个自定义facet把正向金额的格式改成了货币符号在前,完美匹配你输入的€ 456789,12格式。
额外说明
你第二个测试用例1.234,56 EUR能成功解析,是因为这里的货币符号在数值后面,完全符合默认de_DE.utf8的pos_format规则,所以没出问题。
内容的提问来源于stack exchange,提问作者SSteven
相关产品推荐
相关产品推荐

