Sybase ASE 문자열의 UTF-8 바이트수 , 글자수 구하는 함수

Sybase ASE DBMS에서 UTF-8 바이트수 , 글자수 구하는 함수에 대해 살펴본다. Sybase ASE Non-Unicode 인코딩인 EUC-KSC에서 Unicode 인코딩인 UTF-8로 변환하는 프로젝트에서 만들어서 사용했던 함수이다.

* UTF-8 인코딩 참고: UTF-8 – 위키백과, 우리 모두의 백과사전 (wikipedia.org)

EUC-KSC에서 varchar(10)으로 선언된 컬럼을 UTF-8로 변환시 최대 바이트수와 글자수를 확인할 필요가 있는데, 기본으로 제공하는 함수가 없어서 직접 만들어서 사용했다.

UTF-8로 변환시 최대 바이트수와 글자수는 문자열 컬럼의 최대 길이를 얼마로 선언해야 할지 판단하는데 필요하다. 선언된 길이가 아닌 EUC-KSC 인코딩으로 저장된 값에 대해 UTF-8 인코딩으로 변환한 바이트수와 글자수를 계산하여 최대값을 구하는데 이 함수를 사용했다.

DBMS는 Sybase ASE v15.5 에서 테스트했다. 다른 버전에서는 테스트하지 않았으나 잘 동작할 것이라고 본다.

Sybase ASE는 MS-SQL과 매우 유사하여 MS-SQL에서도 별다른 수정없이 그대로 사용할 수 있을 것이다.

1. UTF-8 바이트수 구하기 함수

IF OBJECT_ID('dbo.GET_UTF8_BYTE') IS NOT NULL
  DROP FUNCTION dbo.GET_UTF8_BYTE
GO

CREATE FUNCTION dbo.GET_UTF8_BYTE
(
    @IN_VAL VARCHAR(4000)
)
RETURNS INT
AS
BEGIN
  DECLARE @CHK_LENGTH INT, @I INT, @CHK_BYTE INT, @BYTE_LEN INT, @UTF8_BYTE_LEN INT, @SUM_UTF8_BYTE_LEN INT

  SELECT @I = 1, @CHK_LENGTH = LEN(@IN_VAL), @SUM_UTF8_BYTE_LEN = 0

  WHILE @I <= @CHK_LENGTH
  BEGIN
    SELECT @CHK_BYTE = ASCII(SUBSTRING(@IN_VAL, @I, 1))

    IF @CHK_BYTE >= 128 -- ASCII 코드가 alpha, numeric, control 문자 범위를 넘는 경우(2 Byte 문자일 경우)
        SELECT @BYTE_LEN = 2, @UTF8_BYTE_LEN = 3
    ELSE
        SELECT @BYTE_LEN = 1, @UTF8_BYTE_LEN = 1

    SELECT @SUM_UTF8_BYTE_LEN = @SUM_UTF8_BYTE_LEN + @UTF8_BYTE_LEN, @I = @I + @BYTE_LEN
  END

  RETURN @SUM_UTF8_BYTE_LEN
END
GO

이 코드는 다음과 같은 사실에 기반하여 작성하였다.

  • Non-Unicode 1 Byte의 ASCII 코드가 128 이상이면 2바이트 문자(한,중,일 등)
  • Non-Unicode 한글 1글자(2바이트)는 UTF-8 인코딩에서 3바이트로 저장됨

주요 코드에 대한 설명은 다음과 같다.

  • 18행: 입력 문자열을 한 바이트씩 읽는다.
  • 21행: 읽은 바이트의 ASCII 코드가 128 이상인 경우 건너뛸 바이트 길이를 2로 설정, UTF-8 바이트 수를 3 증가
  • 23행: 읽은 바이트의 ASCII 코드가 128 미만인 경우 건너뛸 바이트 길이를 1로 설정, UTF-8 바이트 수를 1 증가
  • 25행: UTF-8 바이트 수 합계 누적, WHILE 반복문의 조건 변수 @I 값을 건너뛸 바이트 길이 만큼 증가

2. UTF-8 글자수 구하기 함수

위 함수를 다음과 같이 변형하면 UTF-8 바이트 수가 아닌 글자수를 얻을 수 있다.

IF OBJECT_ID('dbo.GET_CHAR_CNT') IS NOT NULL
  DROP FUNCTION dbo.GET_CHAR_CNT
GO

CREATE FUNCTION dbo.GET_CHAR_CNT
(
    @IN_VAL VARCHAR(4000)
)
RETURNS INT
AS
BEGIN
  DECLARE @CHK_LENGTH INT, @I INT, @CHK_BYTE INT, @BYTE_LEN INT, @UTF8_BYTE_LEN INT, @SUM_UTF8_BYTE_LEN INT, @SUM_CHAR_CNT INT

  SELECT @I = 1, @CHK_LENGTH = LEN(@IN_VAL), @SUM_UTF8_BYTE_LEN = 0, @SUM_CHAR_CNT = 0

  WHILE @I <= @CHK_LENGTH
  BEGIN
    SELECT @CHK_BYTE = ASCII(SUBSTRING(@IN_VAL, @I, 1))

    IF @CHK_BYTE >= 128 -- ASCII 코드가 alpha, numeric, control 문자 범위를 넘는 경우(2 Byte 문자일 경우)
        SELECT @BYTE_LEN = 2, @UTF8_BYTE_LEN = 3
    ELSE
        SELECT @BYTE_LEN = 1, @UTF8_BYTE_LEN = 1

    SELECT @SUM_UTF8_BYTE_LEN = @SUM_UTF8_BYTE_LEN + @UTF8_BYTE_LEN, @I = @I + @BYTE_LEN
    SELECT @SUM_CHAR_CNT = @SUM_CHAR_CNT + 1
  END

  --RETURN @SUM_UTF8_BYTE_LEN
  RETURN @SUM_CHAR_CNT
END

16행부터 시작하는 WHILE 반복문은 @I 변수를 조건으로 종료한다. @BYTE_LEN 변수는 읽은 바이트의 ASCII 코드에 따라 2(2 바이트 문자) 또는 1(1 바이트 문자)로 설정되고 25행에서 @I에 더해진다. 이 로직으로  WHILE 반복문은 문자개수만큼 반복 실행된다.

26행에서 @SUM_CHAR_CNT는 1씩 증가시키는 이유는 반복횟수가 문자개수이기 때문이다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

ko_KR한국어