Delphi 带有 UTF8 字符串的 Firebird UDF

Delphi Firebird UDF with UTF8 strings

我们正在尝试在 Delphi(西雅图 10 号)为我们的 Firebird 2.5 数据库编写一个 UDF,它应该从输入字符串中删除一些字符。 我们数据库中的所有字符串字段都使用字符集 UTF8 和排序规则 UNICODE_CI_AI.

该函数应该删除一些字符,例如 space, 。 ; : / \ 和其他字符串。 我们的函数适用于包含 ascii 值 <= 127 的字符的字符串。只要存在 ascii 值大于 127 的字符,UDF 就会失败。 我们尝试使用 PChar 而不是 PAnsiChar 参数但没有成功。现在我们检查字符的 ascii 值是否大于 127,如果是,我们也从字符串中删除该字符。

不过,我们想要的是一个 UDF returns 没有标点符号的原始字符串。

到目前为止,这是我们的代码:

    unit UDFs;

    interface

    uses ib_util;

    function UDF_RemovePunctuations(InputString: PAnsiChar): PAnsiChar; cdecl;

    implementation

    uses SysUtils, AnsiStrings, Classes;

    //FireBird declaration:
    //DECLARE EXTERNAL FUNCTION UDF_REMOVEPUNCTUATIONS
    //  CSTRING(500)
    //RETURNS CSTRING(500) FREE_IT
    //ENTRY_POINT 'UDF_RemovePunctuations' MODULE_NAME 'FB_UDF.dll';
    function UDF_RemovePunctuations(InputString: PAnsiChar): PAnsiChar;
    const
      PunctuationChars = [' ', ',', '.', ';', '/', '\', '''', '"','(', ')'];
    var
      I: Integer;
      S, NewS: String;
    begin
      S := UTF8ToUnicodeString(InputString);

      For I := 1 to Length(S) do
      begin
        If Not CharInSet(S[I], PunctuationChars)
        then begin
          If S[I] <= #127
          then NewS := NewS + S[I];
        end;
      end;

      Result := ib_util_malloc(Length(NewS) + 1);
      NewS := NewS + #0;
      AnsiStrings.StrPCopy(Result, NewS);
    end;

    end.

当我们删除对 ascii 值 <= #127 的检查时,我们可以看到 NewS 包含了它应该包含的所有字符(当然没有标点符号字符)但是在执行我们认为的 StrPCopy 时出现了问题。

如有任何帮助,我们将不胜感激!

多亏了 LU RD 我才开始工作。

答案是将我的字符串变量声明为 Utf8String 而不是 String 并且不将输入字符串转换为 Unicode。

我已经这样调整了我的代码:

    //FireBird declaration:
    //DECLARE EXTERNAL FUNCTION UDF_REMOVEPUNCTUATIONS
    //  CSTRING(500)
    //RETURNS CSTRING(500) FREE_IT
    //ENTRY_POINT 'UDF_RemovePunctuations' MODULE_NAME 'CarfacPlus_UDF.dll';
    function UDF_RemovePunctuations(InputString: PAnsiChar): PAnsiChar;
    const
      PunctuationChars = [' ', ',', '.', ';', '/', '\', '''', '"','(', ')', '-',
                          '+', ':', '<', '>', '=', '[', ']', '{', '}'];
    var
      I: Integer;
      S: Utf8String;
    begin
      S := InputString;

      For I := Length(S) downto 1 do
        If CharInSet(S[I], PunctuationChars)
        then Delete(S, I, 1);

      Result := ib_util_malloc(Length(S) + 1);
      AnsiStrings.StrPCopy(Result, AnsiString(S));
    end;