DB(Database)/Sybase ASE

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

ProDA 2021. 8. 3.

이 글은 새로운 블로그로 옮겼습니다. 5초후 자동으로 이동합니다.

▶ 새로운 블로그 주소: https://prodskill.com/

▶ 새로운 글 주소: https://prodskill.com/sybase-ase-utf8-byte-char-length/

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

DBMS는 Sybase ASE v15.5 이다. MS-SQL과 유사성이 높으므로 MS-SQL에서도 별다른 수정없이 동작할 것이라고 생각한다.

 

▼ 함수 소스 코드

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 값을 건너뛸 바이트 길이 만큼 증가

 

이 함수를 다음과 같이 변형하면 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씩 증가시키는 이유는 반복횟수가 문자개수이기 때문이다.

 

댓글

💲 추천 글