×
Namespaces

Variants
Actions

S60平台简体汉字处理浅谈

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

文章
r60600 在 11 Sep 2007 创建
最后由 hamishwillee 在 15 Dec 2011 编辑

S60应用处理简体汉字一般分为两种情况:

Contents

一.UTF-8编码字串

1.资源文件中的UTF-8编码字串

理论上,从资源文件中获取的字串可以直接用于显示(直接写屏、应用标题、按钮、菜单及各种UI控件)和写文件等操作。但关键是:由于Symbian OS默认编码与Windows等操作系统默认编码不同,所以在Windows等环境中编辑资源源文件(.rss、.rls、.loc)时必须将文件的头部加入CHARACTER_SET UTF8设置,并以UTF-8编码保存,如此编译后的资源文件字串才能得到正常处理。特别是对于汉字这种非ASCII标准字符(这里的ASCII标准字符是指单字节编码字符,汉字是扩展的多字节编码字符,一般为GBK/GB2312编码)。

能将文件以UTF-8编码保存的编辑器有许多(例如Windows的记事本),但最好是用一些16位的编辑器将以UTF-8编码保存的文件开头的3个字节长的字节序标记(Byte Order Mark)删除以便编译系统识别(例如Windows中命令行的Edit),这一点对于S60 3.0平台更是如此。

2.程序文件中的UTF-8编码字串

同样,程序源文件(.cpp)中的字串默认情况下也不是UTF-8编码,如要直接使用也必须以UTF-8编码保存程序源文件。 例如某程序源文件中:

_LIT( KUTF8String, "简体汉字串");
CAknInformationNote* InfoNote;
InfoNote = new ( ELeave ) CAknInformationNote;
InfoNote->ExecuteLD( KUTF8String );

用记事本将此源文件保存为UTF-8编码,这样编译后可正常显示,无需编码转换,不过由于编译环境的识别问题需要注意的是:

1).模拟器平台应用(WINS、WINSCW等)不可将文件开头的字节序标记(Byte Order Mark)删除;

2).真机平台应用(THUMB、ARMI、GCCE等)必须将文件开头的字节序标记(Byte Order Mark)删除。

顺便提一下Carbide中简体汉字的处理,重点是修改工程或文件的文本编码方式。 对于通过.inf或.mmp导入的工程(这种方法比较好),只要导入前源文件符合前面以UTF-8编码保存的那些要求,就不必修改文本编码方式。 而对于新工程,资源源文件中除了加入CHARACTER_SET UTF8设置,最好将源文件的文本编码方式改为UTF-8,否则Carbide将不按UTF-8编码处理文本,显示将不正常。具体方法如下:

1).右键点击工程文件夹的某个资源源文件->properties->Info,将Text file ecoding改为others中的UTF-8;

2).右键点击工程文件夹->properties->Info,将Text file encoding改为others中的UTF-8。

两者取一即可,只是后一种将使工程所有源文件的文本编码方式变为UTF-8。 另外需要注意,Carbide中一旦有文本编码方式的修改,特别是资源源文件,最好重新写入字串,清除(clean)之后再建立应用或运行(build或run),否则上一次的结果仍可能会存在而影响这一次的建立。

二.非UTF-8编码字串

如前所述,如果不以UTF-8编码保存程序源文件,则程序源文件(.cpp)中的字串即为非UTF-8 编码字串。要想正常操作,则必须进行编码转换,但不是转换为UTF-8编码,而是必须转换成Unicode(标准的Unicode也称UTF-16)编码。 例如:

 _LIT8( KNonUnicodeString, "简体汉字串");
TPtrC8 point8( KNonUnicodeString );
CCnvCharacterSetConverter* characterSetConverter=CCnvCharacterSetConverter::NewLC();
//一般简体中文Windows使用的简体汉字编码是Gb2312或Gbk(ASCII字符集的扩展,也称ASCI字符集)
if( converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGbk,
iEikonEnv->FsSession()) == CCnvCharacterSetConverter::EAvailable )
{
}
else if ( characterSetConverter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGb2312,
iEikonEnv->FsSession())!= CCnvCharacterSetConverter::EAvailable )
{
CleanupStack::PopAndDestroy();
User::Leave( KErrNotSupported );
}
TInt state=CCnvCharacterSetConverter::KStateDefault;
HBufC* UnicodeString = HBufC::NewL( point8 );
TPtr16 point16 = UnicodeString->Des();
if( CCnvCharacterSetConverter::EErrorIllFormedInput ==
characterSetConverter->ConvertToUnicode(point16, point8, state ) )
{
CleanupStack::PopAndDestroy();
User::Leave(KErrArgument);
}
CleanupStack::PopAndDestroy(2); // characterSetConverter UnicodeString

UnicodeString即为Unicode编码的字串,可以直接用于显示及写文件等操作。简体汉字串的显示除了编码问题,还要注意字体的选择,特别是对UI控件,最好是用LatinBold12()(2版),AknLayoutUtils::FontFromId( ELatinBold12 )(3版)。简体汉字串显示的相关文档,例程很多,在这里就不多说了。至于文件中读写简体汉字串则要提几点注意:

1.自己写自己读

借助Symbian的文件服务将字串写入文件,一般都是带格式的,文件的首字符用来表示紧跟字串的长度和编码,所以不是什么文件都可以读的,例如用记事本编辑的文件一般就无法正确读出,除非写对了格式,而这种格式手工写是很烦琐的。所以对于程序内部文件读写,最好是:拿什么写就用什么读,要拿什么读就用什么写。

2.UTF-8编码简体汉字串读写文件

无论是从资源文件中读取的,还是.cpp中定义的UTF-8编码字串,都可以直接写直接读,无需编码转换。例如:

 //写文件
_LIT( KFileName, "\\private\\xxxxxxxx\\aTextFile.txt" );
RFs FileServerSession;
User::LeaveIfError(FileServerSession.Connect());
RFile file;
if ( file.Replace(FileServerSession, KFileName, EFileWrite ) != KErrNone )
{
return;
}
CleanupClosePushL( file );
_LIT( KUTF8String, "简体汉字串");//或者HBufC* UTF8ResourceString = StringLoader::LoadLC( R_UTF8_RESOURCE_STRING );
RFileWriteStream StreamWriteToFile( file );
CleanupClosePushL( StreamWriteToFile );
StreamWriteToFile << KUTF8String;//或者StreamWriteToFile << *UTF8ResourceString
CleanupStack::PopAndDestroy(2); //file StreamWriteToFile
 
//读文件
RFs FileServerSession;
RFile file;
User::LeaveIfError(FileServerSession.Connect());
CleanupClosePushL(FileServerSession);
User::LeaveIfError(file.Open(FileServerSession,KHelloFileName, EFileStreamText));
CleanupClosePushL(file);
RFileReadStream StreamReadFromFile(file);
CleanupClosePushL(StreamReadFromFile);
HBufC* StreamData= HBufC::NewLC(StreamReadFromFile, 32);
CleanupStack::PopAndDestroy(3); //file StreamReadFromFile StreamData
FileServerSession.Close();

得到的StreamData可以通过:

 CAknInformationNote* InfoNote;
InfoNote = new ( ELeave ) CAknInformationNote;
InfoNote->ExecuteLD( *StreamData )

加以显示验证。

3.非UTF-8编码简体汉字串读写文件:

如前所述,非UTF8编码简体汉字串必须进行编码转换,主要有两种方法:

  • 1).将字串转换为Unicode编码写入文件后直接读取:
//转换后写文件
 _LIT( KFileName, "\\private\\xxxxxxxx\\aTextFile.txt" );
RFs FileServerSession;
User::LeaveIfError(FileServerSession.Connect());
RFile file;
if ( file.Replace(FileServerSession, KFileName, EFileWrite ) != KErrNone )
{
return;
}
CleanupClosePushL( file );
 
_LIT8( KNonUnicodeString, "简体汉字串");
TPtrC8 point8( KNonUnicodeString );
CCnvCharacterSetConverter* characterSetConverter=CCnvCharacterSetConverter::NewLC();
if( converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGbk,
iEikonEnv->FsSession()) == CCnvCharacterSetConverter::EAvailable )
{
}
else if ( characterSetConverter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGb2312,
iEikonEnv->FsSession())!= CCnvCharacterSetConverter::EAvailable )
{
CleanupStack::PopAndDestroy();
User::Leave( KErrNotSupported );
}
TInt state=CCnvCharacterSetConverter::KStateDefault;
HBufC* UnicodeString = HBufC::NewL( point8 );
TPtr16 point16 = UnicodeString->Des();
if( CCnvCharacterSetConverter::EErrorIllFormedInput ==
characterSetConverter->ConvertToUnicode(point16, point8, state ) )
{
CleanupStack::PopAndDestroy();
User::Leave(KErrArgument);
}
 
RFileWriteStream StreamWriteToFile( file );
CleanupClosePushL( StreamWriteToFile );
StreamWriteToFile << *UnicodeString;
CleanupStack::PopAndDestroy(4);//file StreamWriteToFile characterSetConverter UnicodeString
FileServerSession.Close();


直接读取的方法与UTF-8编码简体汉字串读写文件的读文件操作相同。

  • 2).将字串直接写入文件后再读取转换:

直接写文件的方法与UTF-8编码简体汉字串读写文件的写文件操作相同。

 //读取后转换
RFs FileServerSession;
RFile file;
User::LeaveIfError(FileServerSession.Connect());
CleanupClosePushL(FileServerSession);
User::LeaveIfError(file.Open(FileServerSession,KHelloFileName, EFileStreamText));
CleanupClosePushL(file);
RFileReadStream StreamReadFromFile(file);
CleanupClosePushL(StreamReadFromFile);
HBufC* StreamData = HBufC::NewLC(StreamReadFromFile, 32);
HBufC8* StreamData8 = HBufC8::NewLC( StreamData->Length() );
StreamData8->Des().Copy(*StreamData);
 
TPtrC8 point8( *StreamData8 );
CCnvCharacterSetConverter* characterSetConverter=CCnvCharacterSetConverter::NewLC();
if( converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGbk,
iEikonEnv->FsSession()) == CCnvCharacterSetConverter::EAvailable )
{
}
else if ( characterSetConverter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGb2312,
iEikonEnv->FsSession())!= CCnvCharacterSetConverter::EAvailable )
{
CleanupStack::PopAndDestroy();
User::Leave( KErrNotSupported );
}
TInt state=CCnvCharacterSetConverter::KStateDefault;
HBufC* UnicodeString = HBufC::NewL( point8 );
TPtr16 point16 = UnicodeString->Des();
if( CCnvCharacterSetConverter::EErrorIllFormedInput ==
characterSetConverter->ConvertToUnicode(point16, point8, state ) )
{
CleanupStack::PopAndDestroy();
User::Leave(KErrArgument);
}
 
CleanupStack::PopAndDestroy(6); //file StreamReadFromFile StreamData StreamData8 characterSetConverter UnicodeString
FileServerSession.Close();

得到的UnicodeString可以通过:

 CAknInformationNote* InfoNote;
InfoNote = new ( ELeave ) CAknInformationNote;
InfoNote->ExecuteLD( *UnicodeString );

加以显示验证。

以上代码的集成开发环境为:

Active Perl 5.6.1 build 631

Java Runtime Enviroment v1.5.0_07

CodeWarrior Personal Edition 3.1

S60 3RD EDITION SDK FOR SYMBIAN OS, FOR C++

在以命令行建立的应用中验证正常(WINSCW、GCCE)。如果是其它的建立应用方式或IDE可能需要做相应的变化,或根本不可行,在这里只是给大家提供一种思路和方法。


总之,简体汉字的处理,最重要的在于对字符编码的掌握,说到底就是要依据不同的编码情况进行相应的编码转换操作。最为理想和不受开发环境影响的方法个人认为是:资源文件法,也就是将字符串以UTF-8编码保存在资源源文件中,并设置以UTF-8编码去处理。它最为简便,也最为有效,且便于本地化的移植。其它方法只是提供一种参考,一个可行的方案。

其实,本文所讨论的方法不仅仅对简体汉字有效,理论上对所有非ANSII标准字符都适用。

补记:字节序标记(Byte Order Mark)

BOM(Byte Order Mark),是在Unicode标准(UTF-16)引入后,对于Unicode纯文本文件判断其比特顺序的标记,在UTF-16 Little Endian字节序下为(0xFF,0xFE),在UTF-16 Big Endian下为(0xFE,0xFF);如果进行相应的UTF-16到UTF-8转换,该处两个字节会被处理成为三个字节的UTF-8编码字节序标记。

This page was last modified on 15 December 2011, at 13:10.
191 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×