获取 Sybase ASE 字符串中 UTF-8 字节数和字符数的函数

让我们看一下在 Sybase ASE DBMS 中查找 UTF-8 字节数和字符数的函数。此函数是在从 Sybase ASE 非 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 字节的 ASCII 码为 128 或更高,则 2 字节字符(韩文、中文、日文等)
  • 非 Unicode Hangul 1 个字符(2 个字节)在 UTF-8 编码中存储为 3 个字节

主要代码解释如下。

  • 第 18 行:逐字节读取输入字符串。
  • 第 21 行:如果读取的字节的 ASCII 码大于或等于 128,则设置要跳过的字节长度,将 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(双字节字符)或 1(单字节字符),并添加到第 25 行的@I。按照这个逻辑,WHILE 循环语句会重复执行与字符数一样多的次数。

@SUM_CHAR_CNT之所以在第26行加1,是因为重复的次数是字符数。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

zh_CN简体中文