天天看點

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;

}