cocos2d-x 显示中文字符和解析XML文件 转载
源地址:http://codingnow.cn/cocos2d-x/1038.html
在cocos2d-x中直接显示中文的时候会出现乱码,虽然在实际开发中把字符串直接写在代码里也不是好的做法,但是有时候也是为了更方便了。
本文采用两种方案来解决这个问题:
1. 使用iconv,引擎也提供了这个库,不过只是win32平台,移植到android上还得自己去下载iconv库编译。
2. 把字符串写到xml文件中,然后解析xml文件,格式按照android中的strings.xml
这是一种更好的做法,特别是需要提供国际化支持时。
下面来看具体的实现:
1. 使用iconv库
iconv的作用是将文本在多种国际编码格式之间进行转换。
(1) 首先包含iconv.h头文件,c++->常规->附加包含目录:cocos2dx\platform\third_party\win32\iconv,如图:

(2) 创建头文件IconvString.h,源码:
|
1
2
3
4
5
6
7
8
|
#ifndef ICONV_STRING_H#define ICONV_STRING_Hint convert(char *from_charset, char *to_charset, char *inbuf, size_t inlen, char *outbuf, size_t outlen);int gbk2utf8(char *inbuf, size_t inlen, char *outbuf, size_t outlen);#endif |
(3) 创建源文件IconvString.cpp,源码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include <string>#include "iconv.h"#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) // 编译链接的时候指定静态库#pragma comment(lib,"libiconv.lib") #endifint convert(char *from_charset, char *to_charset, char *inbuf, size_t inlen, char *outbuf, size_t outlen){ iconv_t iconvH; iconvH = iconv_open(to_charset, from_charset); if( !iconvH ) return NULL; memset(outbuf, 0, outlen); #if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) const char *temp = inbuf; const char **pin = &temp; char **pout = &outbuf; if( !iconv(iconvH, pin, &inlen, pout, &outlen) ) { iconv_close(iconvH); return NULL; }#else if( !iconv(iconvH, &inbuf, &inlen, &outbuf, &outlen) ) { iconv_close(iconvH); return NULL; }#endif iconv_close(iconvH); return NULL;}int gbk2utf8(char *inbuf, size_t inlen, char *outbuf, size_t outlen){ return convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen);} |
代码比较简单,需要注意的是win32和android对应的iconv函数参数不一样。在win32平台需要指定lib库,它是iconv.h头文件对应的源码实现。android平台需要下载iconv库,编译的时候在iconv库的根目录下创建一个Android.mk文件就行,Android.mk内容如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
LOCAL_PATH:= $(call my-dir)#libiconv.soinclude $(CLEAR_VARS)LOCAL_MODULE := libiconvLOCAL_CFLAGS := \ -Wno-multichar \ -DAndroid \ -DLIBDIR="c" \ -DBUILDING_LIBICONV \ -DIN_LIBRARYLOCAL_SRC_FILES := \ libcharset/lib/localcharset.c \ lib/iconv.c \ lib/relocatable.cLOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/libcharset \ $(LOCAL_PATH)/lib \ $(LOCAL_PATH)/libcharset/include \ $(LOCAL_PATH)/srclibinclude $(BUILD_STATIC_LIBRARY) |
(4) 下面来看看如何使用,源码:
|
1
2
3
4
5
6
7
8
9
|
char *inBuf = "iconv: 你好,Alex Zhou";size_t inLen = strlen(inBuf);size_t outLen = inLen << 1;char *outBuf = (char *)malloc(outLen);gbk2utf8(inBuf, inLen, outBuf, outLen); CCLabelTTF* pLabel = CCLabelTTF::create(outBuf, "Arial", 30);pLabel->setColor(ccBLACK);free(outBuf); |
要注意转码前后的字符串占的空间是不一样的, 需要知道每种编码格式字符占的字节数:我的vs选择的是Unicode字符集,所以中文字符占2个字节,英文字符占1个字节;gb2312每个字符占2个字节,而UTF-8中文字符占3个字节,英文字符占1个字节。所以这里把存储输出的字符串的数组容量扩大了一部。
效果图:
2. 使用xml的方式
这里使用了引擎提供的CCSAXParser来解析xml,它内部是用libxml2来实现的。
(1) 创建XmlParser.h文件,源码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
#ifndef XML_PARSE_H#define XML_PARSE_H#include <string>#include "cocos2d.h"class XMLParser : public cocos2d::CCObject, public cocos2d::CCSAXDelegator{public: static XMLParser* parseWithFile(const char *xmlFileName); static XMLParser* parseWithString(const char *content); XMLParser(); virtual ~XMLParser(); // 从本地xml文件读取 bool initWithFile(const char *xmlFileName); // 从字符中读取,可用于读取网络中的xml数据 bool initWithString(const char *content); /** *对应xml标签开始,如:<string name="alex">, name为string,atts为string的属性,如["name","alex"] */ virtual void startElement(void *ctx, const char *name, const char **atts); /** *对应xml标签结束,如:</string> */ virtual void endElement(void *ctx, const char *name); /** *对应xml标签文本,如:<string name="alex">Alex Zhou</string>的Alex Zhou */ virtual void textHandler(void *ctx, const char *s, int len); cocos2d::CCString* getString(const char *key);private: cocos2d::CCDictionary *m_pDictionary; std::string m_key; std::string startXMLElement; std::string endXMLElement;};#endif |
代码里已对主要的函数进行了解释,这里就不啰嗦了。
(2) 创建XmlParser.cpp,源码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#include "XMLParser.h"using namespace std;using namespace cocos2d;// 空格const static int SPACE = 32;// 换行const static int NEXTLINE = 10;// tab 横向制表符const static int TAB = 9;XMLParser* XMLParser::parseWithFile(const char *xmlFileName){ XMLParser *pXMLParser = new XMLParser(); if( pXMLParser->initWithFile(xmlFileName) ) { pXMLParser->autorelease(); return pXMLParser; } CC_SAFE_DELETE(pXMLParser); return NULL;}bool XMLParser::initWithFile(const char *xmlFileName){ m_pDictionary = new CCDictionary(); CCSAXParser _parser; _parser.setDelegator(this); const char *fullPath = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(xmlFileName); return _parser.parse(fullPath);}XMLParser* XMLParser::parseWithString(const char *content){ XMLParser *pXMLParser = new XMLParser(); if( pXMLParser->initWithString(content) ) { pXMLParser->autorelease(); return pXMLParser; } CC_SAFE_DELETE(pXMLParser); return NULL;}bool XMLParser::initWithString(const char *content){ m_pDictionary = new CCDictionary(); CCSAXParser _parse; _parse.setDelegator(this); return _parse.parse(content, strlen(content) );}void XMLParser::startElement(void *ctx, const char *name, const char **atts){ this->startXMLElement = (char *)name; CCLog("start=%s", startXMLElement.c_str()); if(this->startXMLElement == "string") { while(atts && *atts) { const char *attsKey = *atts; if(0 == strcmp(attsKey, "name")) { ++ atts; const char *attsValue = *atts; m_key = attsValue; break; } ++ atts; } }}void XMLParser::endElement(void *ctx, const char *name){ this->endXMLElement = (char *)name; CCLog("end=%s", endXMLElement.c_str());}void XMLParser::textHandler(void *ctx, const char *s, int len){ string value((char *)s, 0, len); //是否全是非正常字符 bool noValue = true; for(int i = 0; i < len; ++i) { if(s[i] != SPACE && s[i] != NEXTLINE && s[i] != TAB) { noValue = false; break; } } if(noValue) return; CCString *pString = CCString::create(value); CCLog("key=%s value=%s", m_key.c_str(), pString->getCString()); this->m_pDictionary->setObject(pString, this->m_key);}CCString* XMLParser::getString(const char *key){ string strKey(key); return (CCString *)this->m_pDictionary->objectForKey(strKey);}XMLParser::XMLParser(){}XMLParser::~XMLParser(){ CC_SAFE_DELETE(this->m_pDictionary);} |
如xml部分内容为:
|
1
|
<string name="a">b</string> |
上面的代码的作用是把key=a,value=b存储到字典中。
(3)下面来看看如何使用XmlParser,源码:
|
1
2
3
4
5
6
|
XMLParser *pXmlParser = XMLParser::parseWithFile("strings.xml");CCString *pValue1 = pXmlParser->getString("hello");CCString *pValue2 = pXmlParser->getString("name");CCString *pValue = CCString::createWithFormat("%s%s%s%s", "XML: ", pValue1->getCString(), ",", pValue2->getCString());CCLabelTTF* pLabel = CCLabelTTF::create(pValue->getCString(), "Arial", 30);pLabel->setColor(ccBLACK); |
strings.xml的内容:
|
1
2
3
4
5
|
<?xml version="1.0" encoding="utf-8"?><resources> <string name="hello">你好</string> <string name="name">Alex Zhou</string></resources> |
效果如图:
ok,到这里就结束了,android对应的iconv库我已经打包到源码中了。
源码:http://download.csdn.net/detail/zhoujianghai/5031137
2013年8月11号更新:
有朋友反馈说在xml中的换行符(“\n”)不起作用,原因是XMLParser解析xml时,把”\n”变成了”\\n”,这样就会把换行符原样输出了,解决方法很简单,直接把”\\n”替换成”\n”就可以了,添加一个字符串替换函数。原理:遍历原字符串,查找要替换的字符串在原字符串中的位置pos,然后截取从i到pos的子字符串再跟新字符串拼接,然后更新i,继续查找。在XmlParser.cpp中添加下面的字符串替换函数:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
string replace(string source, string pattern, string dstPattern){ string result; string::size_type pos; int lenSource = source.length(); int i = 0; for(i = 0; i < lenSource; ++i) { pos = source.find(pattern, i); if(string::npos == pos) break; if(pos < lenSource) { string s = source.substr(i, pos - i); result += s; result += dstPattern; i = pos + pattern.length() - 1; } } result += source.substr(i); return result;} |
修改XmlParser.cpp的textHandler函数:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
void XMLParser::textHandler(void *ctx, const char *s, int len){ if(this->m_key.length() == 0) return; string value((char*)s, 0, len); CCLog("s=%s, len=%d", value.c_str(), value.length()); //是否全是非正常字符 bool noValue = true; for(int i = 0; i < value.length(); ++i) { char c = value.at(i); CCLog("v=%d", c); if(c != SPACE && c != NEXTLINE && c != TAB) { noValue = false; break; } } if(noValue) return; string result = replace(value, string("\\n"), string("\n")); CCString *pString = CCString::create(result); CCLog("key=%s value=%s", m_key.c_str(), pString->getCString()); this->m_pDictionary->setObject(pString, this->m_key);} |
更新strings.xml:
|
1
2
3
4
5
|
<?xml version="1.0" encoding="utf-8"?><resources> <string name="hello">你好世界\n</string> <string name="name">Alex Zhou</string></resources> |
运行效果如下图:

cocos2d-x 显示中文字符和解析XML文件 转载的更多相关文章
- PHP页面显示中文字符出现乱码
[出现问题] php页面显示中文字符出现乱码 [解决方法] 在php页面的代码前插入一行代码即可 header("Content-Type: text/html;charset=utf-8& ...
- VS2013 Qt5显示中文字符
VS2013上建立的Qt5project中显示中文字符的两种方式: 1. QStringLiteral("開始") 2. QString::fromLocal8Bit(" ...
- cocos2d-x 3.0 使用Sax解析xml文件(中国显示器问题解决)
今天是个好日子.我以为事情可以变得,明天是个好日子.打开门儿春风... 恩,听着歌写文档生活就是这么享受. 今天曾经的邻居大神突然在qq上赞了我一下,这让我异常激动啊.. 这还要从前前前几天说起,那会 ...
- 【JAVA使用XPath、DOM4J解析XML文件,实现对XML文件的CRUD操作】
一.简介 1.使用XPath可以快速精确定位指定的节点,以实现对XML文件的CRUD操作. 2.去网上下载一个“XPath帮助文档”,以便于查看语法等详细信息,最好是那种有很多实例的那种. 3.学习X ...
- 用dom4j解析xml文件并执行增删改查操作
转自:https://www.aliyun.com/jiaocheng/1339446.html xml文件: <?xml version="1.0" encoding=&q ...
- java解析XML(转载)
使用Dom4j解析XML dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的 ...
- XML:使用DOM技术解析xML文件中的城市,实现select级联选择
中国的城市xml格式:cities.xml <?xml version="1.0" encoding="utf-8"?> <china> ...
- dom4j如何解析XML文件
最近在 一些对xml文件的操作,下面简单写一个dom4j解析xml文件并将其封装到一个javabean中的例子,只是具有针对性的,不是通用的,仅供参考哦~~ 首先说:dom4j是一个java的XML ...
- java解析XML文件
dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源 ...
随机推荐
- TensorFlow安装环境的误区
安装py一定要注意安装的版本,我一开始安装的3.7版本的,现在还没有支持,另外,看清楚自己电脑是32位还是64位的
- element 表单的input循环生成,并可单个input失去焦点单个验证并保存; (多个表单实例)
<div class="box_item"> <el-form ref="aList" :model="form" :ru ...
- GET&&POST请求编码过程
编码.解码 我们在开发过程中不可避免的一个话题就是编码和解码,那么什么是编码什么是解码呢?为什么要进行编码和解码呢?下面我们一一分析! 编码和解码的概念 编码是信息从一种形式或格式转换为另一种形式的过 ...
- 网页后缀html、htm、shtml、shtm有什么区别?
每一个网页或者说是web页都有其固定的后缀名,不同的后缀名对应着不同的文件格式和不同的规则.协议.用法,最常见的web页的后缀名是.html和.htm,但这只是web页最基本的两种文件格式,今天我们来 ...
- socket手写一个简单的web服务端
直接进入正题吧,下面的代码都是我在pycharm中写好,再粘贴上来的 import socket server = socket.socket() server.bind(('127.0.0.1', ...
- 清除.svn文件
清除以.svn结尾的文件: 新建一文本,然后复制以下代码进去,然后保存成clean.bat即可,它会把当前文件夹以及以下的所有匹配文件都给删除了 @echo on color 2f mode con: ...
- 【解决】MacOS下 Python3.7 使用 pyinstaller 打包后执行报错 Failed to execute script pyi_rth__tkinter
Fix tcl/tk libs inclusion in tkinter with Python3.7 under MacOS 使用 Pyinstaller 打包时候报错 3027 ERROR: Tc ...
- linux后台程序开发常用工具
linux开发工具: 1.编辑工具:1)sourceInsight2)Notepad++3)UltraEdit4)Altova XMLSpy 2.linux服务器访问工具:1)FileZilla2)X ...
- 【ospf-链路验证】
根据项目需求搭建好拓扑图 配置RT1的环回口IP和G0/0/0IP地址 开启RT1接口ospf认证,配置接口密码为H3C 配置RT1的ospf区域 同理 开启RT2接口ospf认证,配置接口密码为g0 ...
- 【c学习-9】
/*内存练习*/ #include #include//引入内存分配库文件 int main(){ double* x; //定义整型指针和double指针 int* y; x=(double*)ma ...