linux 宽字符串,linux C 宽字符wchar_t处理

如果字符都是ascii字符,声明成char类型就可以处理了,更节省空间。当遇到中文等非ascii字符时,如果要逐字符处理,这时就需要用到wchar_t了。

一、编码

讲宽字符前,需要了解字符编码。GBK只适合中文,UTF-8适合所有字符。

GBK是双字节编码,详细介绍:http://www.qqxiuzi.cn/zh/hanzi-gbk-bianma.php

UTF-8编码是Unicode的传输形式,也就是说UTF-8便于网络传输。详细介绍:

https://www.zhihu.com/question/22881537

Unicode wikipediahttps://en.wikipedia.org/wiki/Unicode

utf8编码原理详解http://blog.csdn.net/baixiaoshi/article/details/40786503 这篇文章讲的Unicode和uft-8转换,是针对的BMP平面的Unicode,这也是我们通常用到的。Unicode一个平面最多能表示65536个字符,世界上那么多字符,肯定超过65536,所以才有17个平面,能表示1114112个字符。由此看来,Unicode最多有3个字节,当然我们通常遇到的字符都是2个字节的Unicode,也就是在BMP平面。相应的UTF-8编码字节数最多是4个字节,我们通常遇到的字符对应的UTF-8编码是1-3个字节。这就是为什么wchar_t占用内存为4个字节的原因。

二、Linux宽字符处理

对编码有所了解后,我们来看看Linux下的宽字符wchar_t怎么处理。

1. 本地化设置

进行宽字符处理之前,需要调用函数setlocale进行本地化设置。

char *setlocale(int category, const char *locale);

简单起见,category直接填LC_ALL,locale是这种形式的:language[_territory][.codeset][@modifier],我们一般填前3个,比如:zh_CN.UTF-8setlocale(LC_ALL, NULL); // 不设置locale,返回当前locale

setlocale(LC_ALL, ""); // 使用环境变量中的locale

setlocale(LC_ALL, "C") // Linux C程序里面locale一般是"C"

2. 宽字符函数

wcs:wide char string

size_t wcslen(const wchar_t *s); 字符串长度

wchar_t *wmemset(wchar_t *wcs, wchar_t wc, size_t n);  // 注意这个n是宽字符数,而不是字节数。

size_t mbstowcs(wchar_t *dest, const char *src, size_t n); 多字节转宽字符,也就是char*类型的字符串转wchar_t*类型的字符串。

size_t wcstombs(char *dest, const wchar_t *src, size_t n);

int wprintf(const wchar_t *format, ...); 相当于printf,不过打印的宽字符。

这里需要注意的是宽字符输出stream和char类型输出stream不能共用,输出stream的类型由输出的第一字节决定,第一字节是宽字符,那么stream就只能输出宽字符了,调printf不会打印char类型的字符串到终端,需要调用freopen重新打开stdout,才能printf。如下所示:

wprintf(L"1\n");

FILE *p = freopen("/dev/tty", "w", stdout);

if(NULL == p)

fprintf(stderr, "fdopen error: %d, %s\n", errno, strerror(errno));

printf("2\n");

在网上还找到另一种freopen stdout的方式:

#include

string get_file_name (const int fd)

{

if (0 > fd) {

return "";

}

char buf[1024] = {"\0"};

char file_path[PATH_MAX] = {"0"}; // PATH_MAX in limits.h

snprintf(buf, sizeof (buf), "/proc/self/fd/%d", fd);

if (readlink(buf, file_path, sizeof(file_path) - 1) != -1) {

return std::string (file_path);

}

return "";

}

然后这样调用重新打开stdout:

FILE *p = freopen(get_file_name(1).c_str(), "w", stdout);

3. 实例:过滤除大小写字母外的所有字符

string retainAlphabetWchar(const string &strSrc, const string &locale = "zh_CN.UTF-8")

{

int iLen = strSrc.length();

if (strSrc.empty() || 0 == iLen)

{

printf("Input string is empty!\n");

return "";

}

if(iLen > 128)

{

printf("src string is too long, iLen: %d\n", iLen);

return strSrc;

}

// 获取之前的locale

char *pOldLocale = setlocale(LC_ALL, NULL);

if (NULL == pOldLocale)

{

printf("Get old locale info failed!\n");

}

setlocale(LC_ALL, locale.c_str());

wchar_t wcsDst[128];

wmemset(wcsDst, 0, sizeof(wcsDst) / sizeof(wchar_t));

mbstowcs(wcsDst, strSrc.c_str(), iLen);

for (int i = 0; i < wcslen(wcsDst); ++i)

{

wchar_t wcTmp = wcsDst[i];

bool bLegalCharFlag = (wcTmp >= L"a" && wcTmp <= L"z")

|| (wcTmp >= L"A" && wcTmp <= L"Z");

if (!bLegalCharFlag)

{

wcsDst[i] = L" ";

}

}

char cDst[512] = {0};

wcstombs(cDst, wcsDst, sizeof(wcsDst));

string strDst = cDst;

strDst.erase(0, strDst.find_first_not_of(" "));

strDst.erase(strDst.find_last_not_of(" ") + 1);

printf("strSrc string is [%s], strDst string is [%s]\n", strSrc.c_str(), strDst.c_str());

// 恢复之前的locale

setlocale(LC_ALL, pOldLocale);

return strDst;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值