支持UNICODE/UTF8/ANSI之间的转换的类

原文:http://www.ccrun.com/article.asp?i=1023&d=cbj0f7

ZUtf8_16.h文件:
//---------------------------------------------------------------------------
#ifndef ZUtf8_16H
#define ZUtf8_16H

//---------------------------------------------------------------------------
/*
  支持UNICODE,UNICODE BE ,UTF8,ASCII之间的转换的类。
  日期:2007-06-15
  版本:1.0
  作者:小笨象
  网站:http://www.9ele.com
  邮箱:zxjrainbow@9ele.com //不要发垃圾邮件给我~~
  说明:你可以随意使用本文件,不过如果你修改了其中的BUG,
        或者修改得更好了,请你也通知我一下,
        让我也能享受一下开源的好处,谢谢。
*/


enum EncodingType
{
    uni8Bit = 0, // 默认ASCII
    uni16BE = 1,
    uni16LE = 2, // Windows 默认的编码,也就是UNICODE
    uniUTF8 = 3,
    uniUTF8NOBOM = 4 // 没有UTF8标识头的UTF8文件
};

class ZUtf8_16
{
private:
    EncodingType m_unicodeMode; // 编码方式
    int isUTF8_16(const char *s, unsigned int len, unsigned *cchUnused);
    EncodingType __fastcall DetermineEncoding(unsigned char *data, size_t iLen);

public:
    __fastcall ZUtf8_16();
    __fastcall ~ZUtf8_16();
    EncodingType __fastcall GetEncodingType(void){return m_unicodeMode;};
    bool __fastcall LoadFromStream(TMemoryStream *pStream, AnsiString &DestText);
    bool __fastcall StreamSaveToFile(TMemoryStream *pStream,
            AnsiString FileNameA, EncodingType unicodeMode);
};
#endif


ZUtf8_16.cpp文件:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <stdio.h>
#include "ZUtf8_16.h"

#pragma package(smart_init)

__fastcall ZUtf8_16::ZUtf8_16()
{
    m_unicodeMode = uni8Bit;
}
//---------------------------------------------------------------------------
__fastcall ZUtf8_16::~ZUtf8_16()
{
}
//---------------------------------------------------------------------------
int ZUtf8_16::isUTF8_16(const char *s, unsigned int len, unsigned *cchUnused)
{
    int rv = 1;
    int ASCII7only = 1;
    const unsigned char *sx = (unsigned char *)s, *endx = sx+len;
    while(sx < endx)
    {
        if(!*sx)
        {
           // For detection, we'll say that NUL means not UTF8
            ASCII7only = 0;
            rv = 0;
            break;
        }
        else if (*sx < 0x80)
        {
            // 0nnnnnnn If the byte's first hex code begins with 0-7, it is an ASCII character.
            sx++;
        }
        else if (*sx < (0x80 + 0x40))
        {
           // 10nnnnnn 8 through B cannot be first hex codes
            ASCII7only = 0;
            rv = 0;
            break;
        }
        else if(*sx < (0x80 + 0x40 + 0x20))
        {
            // 110xxxvv 10nnnnnn  If it begins with C or D, it is an 11 bit character
            ASCII7only = 0;
            if(sx >= endx-1) break;
            if(!(*sx & 0x1F) || (sx[1]&(0x80+0x40)) != 0x80) { rv = 0; break; }
            sx += 2;
        }
        else if (*sx < (0x80 + 0x40 + 0x20 + 0x10))
        {
            // 1110qqqq 10xxxxvv 10nnnnnn If it begins with E, it is 16 bit
            ASCII7only = 0;
            if(sx >= endx-2) break;
            if(!(*sx & 0xF) || (sx[1]&(0x80+0x40)) != 0x80 || (sx[2]&(0x80+0x40)) != 0x80)
            { rv = 0; break; }
            sx += 3;
        }
        else
        {
            /* more than 16 bits are not allowed here */
            ASCII7only = 0;
            rv = 0;
            break;
        }
    }
    if(cchUnused) *cchUnused = endx-sx;
    return(ASCII7only?0:rv);
}
//---------------------------------------------------------------------------
EncodingType __fastcall ZUtf8_16::DetermineEncoding(unsigned char *data, size_t iLen)
{
    // TODO:判断当前文件的编码类型。
    m_unicodeMode = uni8Bit; // 默认ASCII
    if(data[0] == 0xFE && data[1] == 0xFF) // Big endian == UNICODE-BIG   UTF16
    {
        m_unicodeMode = uni16BE;
    }
    else if(data[0] == 0xFF && data[1] == 0xFE) // Little endian == UNICODE  UTF16
    {
        m_unicodeMode = uni16LE; // Unicode
    }
    else if(data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) // UTF8
    {
        m_unicodeMode = uniUTF8;
    }
    else if(isUTF8_16(data, iLen, NULL) == 1)
    {
        m_unicodeMode = uniUTF8NOBOM;
    }
    return  m_unicodeMode;
}
//---------------------------------------------------------------------------
bool __fastcall ZUtf8_16::LoadFromStream(TMemoryStream *pSourceStream, AnsiString &DestText)
{
    // TODO:从流中读取数据
    // 先判断字符编码
    pSourceStream->Position = 0;
    if(pSourceStream->Size == 0) return true;
// 本文转自 C++Builder 研究 - http://www.ccrun.com/article.asp?i=1023&d=cbj0f7
    m_unicodeMode = DetermineEncoding((char*)pSourceStream->Memory, pSourceStream->Size);

    pSourceStream->Position = 0;

    // 再根椐相应的编码做相应的事。
    switch(m_unicodeMode)
    {
        case uni8Bit:
        {
           
// 什么都不做。以保证打开一些大的文件时速度快一些。
            // 所以调用者需要自己在调的之后判断字符编码,
            // 如果是uni8Bit,则需要自己处理。
//            int iLength = pSourceStream->Size ;
//            char  *szUnicode = new char[iLength+1];
//            memset(szUnicode, 0x00, iLength+1);
//            pSourceStream->Read(szUnicode, iLength);
//            DestText = AnsiString(szUnicode);
//            delete []szUnicode;
//            szUnicode = NULL;

            break;
        }
        case uni16BE: 
        {
           // UC Big endian
            pSourceStream->Position = 2;
            int iLength = pSourceStream->Size-2 ;
            char temp;
            char *szUnicode = new char[iLength+2];
            memset(szUnicode, 0x00, iLength+2);
            pSourceStream->Read(szUnicode, iLength);
           // 只要把每两个字节的位置交换一下,就是UNICODE LE了。So...
            for(int i = 0; i<iLength; i += 2)
            {
                temp = szUnicode[i];
                szUnicode[i] = szUnicode[i+1];
                szUnicode[i+1] = temp;
                Application->ProcessMessages();
            }

            DestText = WideCharLenToString ((wchar_t*)(szUnicode), iLength/2);

            delete []szUnicode;
            szUnicode = NULL;

            break;
        }
        case uni16LE:
        {
           // UNICODE  Little endian
            pSourceStream->Position = 2;
            int iLength = pSourceStream->Size-2 ;

            wchar_t  *szUnicode = new wchar_t[iLength+2];
            memset(szUnicode, 0x00, iLength+2);
            pSourceStream->Read(szUnicode, iLength);
            WideString WideStr = WideString(szUnicode);
            DestText = WideStr;

            delete []szUnicode;
            szUnicode = NULL;

            break;
        }
        case uniUTF8:
        {
           // UTF8
            pSourceStream->Position = 3;
            int iLength = pSourceStream->Size-3 ;
            char *szUTF8 = new char[iLength+3];
            memset(szUTF8, 0x00, iLength+3);
            pSourceStream->Read(szUTF8, iLength);

            AnsiString Utf8Str = Utf8ToAnsi(szUTF8);
            if(Utf8Str == "")
                DestText = AnsiString((char*)pSourceStream->Memory);
            else
                DestText = Utf8Str;
            delete []szUTF8;
            szUTF8 = NULL;
            break;
        }
        case uniUTF8NOBOM:
        {
           // UTF8 没有头标识的情况。
            int iLength = pSourceStream->Size;
            char *szUTF8 = new char[iLength+3];
            memset(szUTF8, 0x00, iLength+3);
            pSourceStream->Read(szUTF8, iLength);

            AnsiString Utf8Str = Utf8ToAnsi(szUTF8);
            if(Utf8Str == "")
                DestText = AnsiString((char*)pSourceStream->Memory);
            else
                DestText = Utf8Str;
            delete []szUTF8;
            szUTF8 = NULL;
            break;
        }

    }
    return true;
}
//---------------------------------------------------------------------------
bool __fastcall ZUtf8_16::StreamSaveToFile(TMemoryStream *pStream, 
        AnsiString FileNameA, EncodingType unicodeMode)
{
    // TODO:把流内容按指定的格式保存到文件中。
    try
    {
        pStream->Position = 0;
        switch(unicodeMode)
        {
            case uni8Bit:
            {
               // 什么都不做。直接保存。
                pStream->SaveToFile(FileNameA);
                break;
            }
            case uni16BE:
            {
                // UC Big endian
                int iLength = pStream->Size ;
                char temp;
                char *pSource = new char[iLength+2];
                memset(pSource, 0x00, iLength+2);
                pStream->Read(pSource, iLength);

                // 先看看转成的宽字节数返到nLen
                int nLen = MultiByteToWideChar( CP_ACP, 0, pSource, iLength, NULL, NULL );
                LPWSTR lpwsz = new WCHAR[nLen];
                MultiByteToWideChar( CP_ACP, 0, pSource, -1, lpwsz, nLen );

                int iNewLen = lstrlenW(lpwsz) * sizeof(WCHAR);
                char *pDest = new char[iNewLen];
                memcpy(pDest, lpwsz, iNewLen);
               
                // 只要把每两个字节的位置交换一下,就是UNICODE Big了。So...
                for(int i = 0; i<iNewLen; i += 2)
                {
                    temp = pDest[i];
                    pDest[i] = pDest[i+1];
                    pDest[i+1] = temp;
                    Application->ProcessMessages();
                }

                FILE *f = fopen(FileNameA.c_str(), "wb");
                // 写Unicode Big头
                fputc(0xFE, f);
                fputc(0xFF, f);
                fwrite(pDest, 1, iNewLen, f);
                fclose(f);

                delete []pDest;
                pDest = NULL;
                delete []lpwsz;
                lpwsz = NULL;
                delete []pSource;
                pSource = NULL;

                break;
            }
            case uni16LE:
            {
                // UNICODE  Little endian
                int iLength = pStream->Size ;
                char *pSource = new char[iLength+2];
                memset(pSource, 0x00, iLength+2);
                pStream->Read(pSource, iLength);

                // 先看看转成的宽字节数返到nLen
                int nLen = MultiByteToWideChar( CP_ACP, 0, pSource, iLength, NULL, NULL );
                LPWSTR lpwsz = new WCHAR[nLen];
                MultiByteToWideChar( CP_ACP, 0, pSource, -1, lpwsz, nLen );

                FILE *f = fopen(FileNameA.c_str(), "wb");
                // 写Unicode头
                fputc(0xFF, f);
                fputc(0xFE, f);
                // 一个宽字节占两个字节
                fwrite(lpwsz, 1, lstrlenW(lpwsz) * sizeof(WCHAR), f);
                fclose(f);

                delete []lpwsz;
                lpwsz = NULL;
                delete []pSource;
                pSource = NULL;
                break;
            }
            case uniUTF8:
            {
                // UTF8
                int iLen = pStream->Size;
                char *pSource = new char[iLen+3];
                memset(pSource, 0x00, iLen+3);
                pStream->Read(pSource, iLen);

                AnsiString Utf8Str = AnsiToUtf8(pSource);

                delete []pSource;
                pSource = NULL;
                FILE *f = fopen(FileNameA.c_str(), "wb");
                // 写UTF8头
                fputc(0xEF, f);
                fputc(0xBB, f);
                fputc(0xBF, f);
                // 一个宽字节占两个字节
                fwrite(Utf8Str.c_str(), 1, Utf8Str.Length(), f);
                fclose(f);
                break;
            }
            case uniUTF8NOBOM:
            {
                // UTF8没有标识头的情况。
                int iLen = pStream->Size;
                char *pSource = new char[iLen+3];
                memset(pSource, 0x00, iLen+3);
                pStream->Read(pSource, iLen);

                AnsiString Utf8Str = AnsiToUtf8(pSource);

                delete []pSource;
                pSource = NULL;
                FILE *f = fopen(FileNameA.c_str(), "wb");
                // 一个宽字节占两个字节
                fwrite(Utf8Str.c_str(), 1, Utf8Str.Length(), f);
                fclose(f);
                break;
            }
        } // end of switch
    }
    catch(...)
    {
        return false;
    }
    return true;
}
//---------------------------------------------------------------------------
// 试用举例:
#include "ZUtf8_16.h"
bool __fastcall LoadFile(AnsiString strFileName, TStrings *pList)
{
    EncodingType unicodeMode;
    // TODO:装入文件。
    // 如果装入成功,则返回true
    AnsiString ErrMsg;
    bool bReturn = true;
    ErrMsg.sprintf("装入 %s 文档时出错,/n/n该文档不存在"
                   "或者被其它程序以独占方式打开!", strFileName);

    if(!FileExists(strFileName))
    {
        MessageBox(0,  ErrMsg.c_str(), "错误", MB_OK|MB_ICONERROR);
        return false;
    }
    AnsiString ReturnTxt;
    ZUtf8_16 zutf8_16;

    TMemoryStream *ReadStream = new TMemoryStream();
    ReadStream->LoadFromFile(strFileName);
    bReturn = zutf8_16.LoadFromStream(ReadStream, ReturnTxt);
    if(bReturn)
    {
        unicodeMode = zutf8_16.GetEncodingType();
        if(unicodeMode==uni8Bit)
           pList->LoadFromStream(ReadStream);
        else
            pList->Text = ReturnTxt;
    }
    else
    {
        MessageBox(0,  ErrMsg.c_str(), "错误", MB_OK|MB_ICONERROR);
    }
    delete ReadStream;
    ReadStream = NULL;

    return bReturn;
}

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值