我有这个C代码:
locale_t myLocale = newlocale(LC_NUMERIC_MASK, "en_US", (locale_t) 0);
uselocale(myLocale);
ptrLocale = localeconv();
ptrLocale->thousands_sep = (char *) "'";
int i1 = snprintf( s1, sizeof(s1), "%'d", 123456789);
s1
中的输出为123,456,789
。
即使我将->thousands_sep
设置为'
,也会被忽略。有没有办法将任何字符设置为千位分隔符?
答案 0 :(得分:3)
功能localeconv()
只需阅读定位设置,ptrLocale->thousands_sep
本身不会更改当前区域设置的设置。
修改强>
我不知道如何在C中执行此操作,但可以找到许多带有C ++输出的示例。 请参阅C ++中的以下示例:
#include <iostream>
#include <locale>
using namespace std;
struct myseps : numpunct<char> {
// use ' as separator
char do_thousands_sep() const { return '\''; }
// digits are grouped by 3
string do_grouping() const { return "\3"; }
};
int main() {
cout.imbue(locale(locale(), new myseps));
cout << 1234567; // the result will be 1'234'567
}
编辑2:
C ++参考文献说:
localeconv()返回一个指向struct lconv类型的填充对象的指针。对象中包含的值可以通过后续调用localeconv来覆盖,而不是直接修改对象。使用LC_ALL,LC_MONETARY或LC_NUMERIC的类别值调用setlocale会覆盖结构的内容。
我在MS Visual Studio 2012中尝试了以下示例(我知道这是不好的和不安全的样式):
#include <stdio.h>
#include <locale.h>
#include <string.h>
int main() {
setlocale(LC_NUMERIC, "");
struct lconv *ptrLocale = localeconv();
strcpy(ptrLocale->decimal_point, ":");
strcpy(ptrLocale->thousands_sep, "'");
char str[20];
printf("%10.3lf \n", 13000.26);
return 0;
}
我看到了结果:
13000:260
因此,可以假设通过decimal_point
收到的指针可以更改thousands_sep
和localeconv()
,但printf
会忽略thousands_sep
。< / p>
编辑3:
更新了C ++示例:
#include <iostream>
#include <locale>
#include <sstream>
using namespace std;
struct myseps : numpunct<char> {
// use ' as separator
char do_thousands_sep() const { return '\''; }
// digits are grouped by 3
string do_grouping() const { return "\3"; }
};
int main() {
stringstream ss;
ss.imbue(locale(locale(), new myseps));
ss << 1234567; // printing to string stream with formating
printf("%s\n", ss.str().c_str()); // just output when ss.str() provide string, and c_str() converts it to char*
}
答案 1 :(得分:3)
如何更改printf()
的千位分隔符:
configure --prefix=/usr/glibc-version
命令make -j 8
make
输出setMyThousandSeparator.c
- 内容见下文setMyThousandSeparator("'")
来电之前,您正常的C源代码调用printf()
函数中的setMyThousandSeparator.o
与您的项目联系起来。目前我在链接libc
静态时尝试了它,但它确实有效。
setMyThousandSeparator.c
的内容:
#include <locale/localeinfo.h>
void setMyThousandSeparator(char * sMySeparator)
{
_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP) = sMySeparator;
}
<强>的信息:强>
此解决方案是线程安全的,因为它正在访问与printf()
相同的数据!
答案 2 :(得分:1)
这是一个非常简单的解决方案,适用于每个Linux发行版,并且不需要 - 作为我的第一个答案 - glibc
hack:
所有这些步骤必须在构建目录中的 origin glibc
目录 - NOT 中执行 - 在使用glibc
版本构建后这个instructions建议的单独构建目录。
我的新locale
文件名为en_AT
。
localedata/locales/
的{{1}}目录中创建新文件en_US
。en_AT
的所有条目更改为thousands_sep
或您希望拥有的任何字符作为千位分隔符。thousands_sep "<U0027>"
更改为en_US
。en_AT
添加到文件localedata/SUPPORTED
。en_AT.UTF-8/UTF-8 \
。make localedata/install-locales
会自动添加到系统中,并且 即时 可供该计划使用。在C / C ++程序中,您可以切换到新的千位分隔符:
locale
使用setlocale( LC_ALL, "en_AT.UTF-8" );
生成此输出
1&#39; 000&#39; 000
备注:当您在程序中需要在运行时确定的不同本地化时,您可以在printf( "%'d", 1000000 );
页面中使用此example来加载请求的man
1}}只需替换locale
中的LC_NUMERIC
设置。
答案 3 :(得分:0)
此答案来自VolAnd's one。
根据this source,千分隔符仅与非标准'
标志一起使用。
因此,如果您的printf
与POSIX.1-2008兼容,则可以使用:
setlocale(LC_NUMERIC, "");
struct lconv *ptrLocale = localeconv();
ptrLocale->decimal_point = ":";
ptrLocale->thousands_sep = "'";
char str[20];
printf("%'10.3lf \n", 13000.26);
return 0;
答案 4 :(得分:0)
这是我用于uint64_t类型的专用C函数,但是可以很容易地将其泛化。基本上,它会将一千个分隔符插入到snprintf()生成的字符串中。
此方法与LOCALE,使用的C标准等无关-当然,您不必重新编译GNU libc;)
#if __WORDSIZE == 64
#define PRT_U64 "lu"
#else
#define PRT_U64 "llu"
#endif
char* th_sep_u64(uint64_t val, char* buf) {
char tmpbuf[32]; //18'446'744'073'709'551'615 -> 26 chars
int nch, toffs, pos;
pos = 1;
toffs = 31;
nch = snprintf(tmpbuf, 32, "%"PRT_U64, val);
nch -- ;
buf[toffs] = 0;
for (; nch>=0; --nch) {
toffs -- ;
buf[toffs] = tmpbuf[nch];
if ((0 == (pos % 3)) && (nch > 0)) {
toffs -- ;
buf[toffs] = '\''; //inject the separator
}
pos ++ ;
}
buf += toffs;
return buf;
}
用法:
{
char cbuf[32];
uint64_t val = 0xFFFFFFFFFFFFFFFFll;
printf("%s", th_sep_u64(val, cbuf));
//result: 18'446'744'073'709'551'615
}
致谢