C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[362] 문자열을 C언어 표현으로 상호 변환하기
김상구.패패루 [peperu] 9738 읽음    2002-09-03 23:01
Q&A에 문자열을 C언어에서의 문자열 표현 방식으로 바꾸고
반대로 C언어에서의 문자열 표현 방식을 실제 컴파일된 문자열로 바꾸는
그런 함수가 있는지 질문을 했더니 없다는 것이 중론인 것 같네요..

당장 필요하긴 하고 해서 그냥 만들었습니다.
함수 이름은 좀 고민스럽습니다. 일단 소스코드상의 표현을 Src라고
보고, 컴파일된 후의 문자열을 Str라고 봐서 SrcToStr, StrToSrc라고
이름은 지었는데 좋은 이름 추천좀 해 주세요.

혹시나 이런 비슷한 함수가 API나 Ansi C++에 있다면
김백일님.. 각오하십시오.. 백일님이 없다고 해서 만든거니까 삽질하게
한 대가를 톡톡히 치르셔야 할겁니다. ^^ ㅋㅋㅋ

특이점이라고 할 것 까지는 없지만 일단 디코딩 함수인 SrcToStr은
다음과 기능을 제공합니다.

1. 기본 확장 문자코드 지원
  \n \t \v \b \r \a \\ \? \' \" 총 10개의 확장문자코드를 지원합니다.
2. Octal표현 지원
  \040  :8진수로 스페이스죠..
  이와 같은 표현을 지원합니다. 숫자의 범위를 정확히 검사하므로 안전
  하게 동작합니다. \510 과 같이 256범위를 벗어나거나 \108 과 같이
  8진수로 표현 불가능한 경우도 걸러냅니다.
3. Hex 표현 지원
  \x2f 과 같은 16진수 표현을 지원합니다.
4. 만일 디코딩에 성공했다면 반환값은 0입니다.
   만일 디코딩시에 오류가 발견된다면 반환값은 오류가 난 지점(1베이스)
   입니다. 따라서 Syntex에러를 표시할 때 처럼 에러 위치를 비교적 근
   접하게 표시해 줄 수 있겠죠.
5. DBCS에서 안전하게 동작합니다.
   즉, 한글에 대해서도 안전하다는 얘기입니다. 단, 2byte이상의 MBCS
   스트링에 대해서는 오동작의 가능성이 있습니다.

인코딩 함수인 StrToSrc는 다음과 같은 기능을 제공합니다.
1. 일반 가시문자가 아닌 것들에 대한 인코딩 - 16진수 표현을 사용합니다.
   8진수 표기보다는 16진수가 보다 익숙한 것 같아서 16진수 표현으로 통
   일했습니다.
2. 확장 문자코드를 지원하는 경우 16진수 표현을 쓰지 않고 확장 문자코드
   표현을 사용합니다.
   즉, 0x0C (\r) 의 경우 \x0c로 인코딩 하지 않고 \r로 인코딩합니다.
   단, \?의 경우 일반적으로 인코딩을 하지 않기 때문에 그냥 ?로 표기합니다.
3. 반환값은 항상 0입니다. (언제나 성공할 수 있으므로)


개선해야할 사항은 다음과 같습니다.

1. 함수 이름이 정말 맘에 안듭니다. 이름을 바꾸고 싶습니다.
2. 결과값에 대해 SetLength() 함수로 길이를 조절하므로 1회의 메모리 복
   사가 발생합니다. 당연히 효율이 좀 떨어지겠죠.
   디코딩 루틴인 SrcToStr의 경우 큰 문제가 없지만 인코딩 루틴인
   StrToSrc 함수는 심각합니다.
   안전빵으로 입력값의 길이의 4배만큼 길이를 확보하고 인코딩 한 다음
   최종길이 만큼 재조정하는 무식한 구조입니다. 이에 대한 개선이 필요
   합니다.
3. 루프가 좀 지저분합니다.
   시간이 없어서 대충 만들다보니.. 인코딩쪽하고 디코딩쪽이 루프 돌리
   는게 서로 다릅니다. ㅠ ㅠ 하나는 while을 쓰고 다른 하나는 for를
   씁니다.
   일반적으로 while을 쓰는 것이 속도는 빠르지만 DBCS를 지원하려면
   IsLeadByte()를 써야 하기 때문에 for가 더 유리해 보입니다.
   한쪽에서는 IsLeadByte 호출이 많아서 for를 썼습니다.
   제가 알기론 IsLeadByte는 상당히 비싼 함수로 알고 있습니다. 엄청
   신경이 쓰입니다.
4. 무식한 탐색 함수들이 2개 있습니다. 스탠다드 C의 함수로도 처리 가능
   한 것인데 이름을 까먹어서 찾기도 귀찮고 해서 그냥 대충 만들었습
   니다.
5. 뭐, 결론은 전반적으로 코드 최적화를 해야 한다.. 였습니다.

좀 더 개선해 주실 수 있는 분은 직접 수정하신 후 다시 올려주시면 고맙
겠습니다.


덤으로 HexEncode라는 함수와 HexDecode라는 함수가 같이 있습니다.
이건 VCL의 HexToBin, BinToHex 함수와 동일한 기능을 하지만 대소문자를
선택할 수 있습니다. VCL의 경우 소문자만 지원하죠.

사용예제1:
String sSrc = "헤헤헤\r\nTest임다";
String sDest;
StrToSrc(sDest,sSrc);
ShowMessage(sDest);

-- 메시지박스에 표시되는 문자:
헤헤헤\r\nTest임다

사용예제2:
String sSrc = "헤헤헤\\r\\nTest임다";
String sDest;
SrcToStr(sDest,sSrc);
ShowMessage(sDest);

-- 메시지박스에 표시되는 문자:
헤헤헤
Test임다



먼저 헤더 파일에는..

int __fastcall HexEncodeOpt(bool UseLowerCase);
int __fastcall HexEncode(String &Dest, const String& Src);
int __fastcall HexEncode(char *Dest, char *Src, int SrcSize);
int __fastcall HexDecode(String &Dest, const String& Src);
int __fastcall HexDecode(char *Dest, char *Src, int SrcSize);

int __fastcall SrcToStr(String &Dest, const String &Src);
int __fastcall StrToSrc(String &Dest, const String &Src);


요기까지..
cpp파일에는


static Byte HexEncodeTable[] = "0123456789ABCDEF";
static Byte HexEncodeTable2[] = "0123456789abcdef";
static Byte *HexTableSelected = HexEncodeTable;
static Byte HexDecodeTable[] = {                         0, 1,
                                 2, 3, 4, 5, 6, 7, 8, 9, 0, 0,
                                 0, 0, 0, 0, 0,10,11,12,13,14,
                                15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                 0, 0, 0, 0, 0, 0, 0,10,11,12,
                                13,14,15 };
static Byte ExtCodeKey[] = "ntvbra\\?\'\"";
static Byte ExtCodeValue[] = {10,9,11,8,13,7,92,63,39,34,0};

//---------------------------------------------------------------------------
int __fastcall HexEncodeOpt(bool UseLowerCase)
{
  if (UseLowerCase)
  {
    HexTableSelected = HexEncodeTable2;
  }
  else
  {
    HexTableSelected = HexEncodeTable;
  }
}
//---------------------------------------------------------------------------
int __fastcall HexEncode(String &Dest, const String& Src)
{
  Dest.SetLength(Src.Length() * 2);
  return HexEncode(Dest.c_str(), Src.c_str(), Src.Length());
}
//---------------------------------------------------------------------------
int __fastcall HexEncode(char *Dest, char *Src, int SrcSize)
{
  Byte *pPtr = Src;
  Byte *pEnd = pPtr+SrcSize;
  while (pPtr < pEnd)
  {
    *Dest = HexTableSelected[(*pPtr) >> 4];
    *(Dest+1) = HexTableSelected[(*pPtr) & 0x0F];
    pPtr ++;
    Dest += 2;
  }
  return SrcSize * 2;
}
//---------------------------------------------------------------------------
int __fastcall HexDecode(String &Dest, const String& Src)
{
  Dest.SetLength(Src.Length() / 2);
  return HexDecode(Dest.c_str(), Src.c_str(), Src.Length());
}
//---------------------------------------------------------------------------
int __fastcall HexDecode(char *Dest, char *Src, int SrcSize)
{
  Byte *pPtr = Src;
  Byte *pEnd = pPtr+SrcSize;
  while (pPtr < pEnd)
  {
    *Dest = (HexTableSelected[(*pPtr)-48] << 4) | (HexTableSelected[(*(pPtr+1))-48]);
    pPtr += 2;
    Dest++;
  }
  return SrcSize / 2;
}
//---------------------------------------------------------------------------




//---------------------------------------------------------------------------
Byte GetExtCodeValue(Byte *pPos)
{
  Byte Value = *pPos;
  Byte *pPtr = ExtCodeKey;
  while (*pPtr)
  {
    if (*pPtr == Value)
      return ExtCodeValue[pPtr - ExtCodeKey];
    pPtr++;
  }
  return 0;
}
//---------------------------------------------------------------------------
Byte GetExtCodeKey(Byte Value)
{
  Byte *pPtr = ExtCodeValue;
  while (*pPtr)
  {
    if (*pPtr == Value)
      return ExtCodeKey[pPtr - ExtCodeValue];
    pPtr++;
  }
  return 0;
}
//---------------------------------------------------------------------------
bool IsHex(Byte* pPos)
{
  if (*(pPos) == 'x')
  {
    for (int ii = 1; ii <= 2; ii++)
    {
      Byte Value = *(pPos+ii);
      if ((Value < '0' || Value > '9') && (Value < 'a' || Value > 'f'))
        return false;
    }
    return true;
  }
  else
    return false;
}
//---------------------------------------------------------------------------
bool IsOct(Byte* pPos)
{
  Byte Value = *(pPos);
  if (Value >= '0' && Value < '4')
  {
    for (int ii = 1; ii <= 2; ii++)
    {
      Byte Value = *(pPos+ii);
      if (Value < '0' || Value >= '8')
        return false;
    }
    return true;
  }
  else
    return false;
}
//---------------------------------------------------------------------------
int __fastcall SrcToStr(String &Dest, const String &Src)
{
  Dest.SetLength(Src.Length());

  Byte *pPtr = Src.c_str();
  Byte *pDest = Dest.c_str();
  Byte *pEnd = pPtr + Src.Length();
  while (pPtr < pEnd)
  {
    if (*pPtr == '\\' && !(Src.IsTrailByte(pPtr - Src.c_str() + 1)))
    {
      if (IsHex(pPtr+1))
      {
        *pDest = (HexDecodeTable[(*(pPtr+2))-48] << 4) | (HexDecodeTable[(*(pPtr+3))-48]);
        pPtr += 4;
      }
      else
      {
        if (IsOct(pPtr+1))
        {
          *pDest = ((*(pPtr+1)-48) << 6) | ((*(pPtr+2)-48) << 3) | (*(pPtr+3)-48);
          pPtr += 4;
        }
        else
        {
          Byte Value = GetExtCodeValue(pPtr+1);
          if (Value)
            *pDest = Value;
          else
            return Src.c_str() - pPtr + 1;
          pPtr += 2;
        }
      }
    }
    else
    {
      *pDest = *pPtr;
      pPtr++;
    }
    pDest ++;
  }

  if (pDest - Dest.c_str() != Dest.Length())
    Dest.SetLength(pDest - Dest.c_str());
  return 0;
}
//---------------------------------------------------------------------------
int __fastcall StrToSrc(String &Dest, const String &Src)
{
  Dest.SetLength(Src.Length()*4);

  Byte *pDest = Dest.c_str();
  Byte cValue;

  int nSrcLen = Src.Length();

  for (int ii = 1; ii <= nSrcLen; ii++)
  {
    cValue = Src[ii];
    if (cValue < ' ' || cValue > '~' || cValue == '\\' || cValue == '\"')
       // 제어코드가 있을 가능성이 있는 경우
    {
      if (Src.IsLeadByte(ii))
      {
        *pDest = cValue;
        *(pDest+1) = Src[ii+1];
        pDest += 2;
        ii++;
        continue;
      }
      else
      {
        *pDest = '\\';
        pDest ++;
        Byte cKey = GetExtCodeKey(cValue);
        if (cKey) // 제어 코드가 있는 경우
        {
          *pDest = cKey;
          pDest ++;
        }
        else
        {
          // 제어 코드가 없는 경우
          *(pDest) = 'x';
          *(pDest+1) = HexEncodeTable[cValue >> 4];
          *(pDest+2) = HexEncodeTable[cValue & 0x0F];
          pDest += 3;
        }
      }
    }
    else
    {
      *pDest = cValue;
      pDest ++;
    }
  }

  if (pDest - Dest.c_str() != Dest.Length())
    Dest.SetLength(pDest - Dest.c_str());
  return 0;
}
//---------------------------------------------------------------------------


+ -

관련 글 리스트
362 문자열을 C언어 표현으로 상호 변환하기 김상구.패패루 9738 2002/09/03
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.