Как я могу отфильтровать строковое поле в наборе данных с помощью предложения like и умлаута?

Хотя есть некоторая документация по фильтрации наборов данных, детали синтаксиса только обрисованы в общих чертах. В моем приложении я хочу фильтровать имена людей с помощью фильтра набора данных. Обычно это работает очень быстро, но я наткнулся на небольшую проблему фильтрации, например TClientDataset, Как я могу добавить подобный фильтр для умлаута? Выражение

[X] LIKE 'Ö%'

(для данного поля X) не работает (в отличие от выражения [X] LIKE 'A%'). Это просто ошибка или мне нужно где-нибудь установить кодировку / кодировку?

Минимальный пример:

procedure TForm1.FormCreate(Sender: TObject);
var
  LField: TFieldDef;
  LCDs: TClientDataSet;
const
  SAMPLE_CHAR: string = 'Ö';
begin
  LCds := TClientDataSet.Create(Self);
  LField := LCds.FieldDefs.AddFieldDef();
  LField.DataType := ftString;
  LField.Size := 10;
  LField.Name := 'X';
  LCDs.CreateDataSet;
  LCDs.Append;
  LCDs.FieldByName('X').AsString := SAMPLE_CHAR;
  LCDs.Post;

  ShowMessage(LCds.FieldByName('X').AsString);
  LCds.Filter := '[X] LIKE ' + QuotedStr(SAMPLE_CHAR + '%');
  LCds.Filtered := true;
  ShowMessage(LCds.FieldByName('X').AsString);
end;

Первое окно сообщения показывает Öтогда как второе окно сообщения пусто. Если вы измените SAMPLE_CHAR от Ö в A, оба сообщения показывают A,

1 ответ

Решение

Используйте тип данных ftWideString для создания поля TWideStringField вместо ftString, которое внутренне создает поле TStringField. TStringField предназначен для строк ANSI, а TWideStringField для строк Unicode. Сделайте это, иначе вы потеряете данные.

Для доступа к значению TWideStringField используйте свойство AsWideString. Я провел быстрый тест в 2009 году, и когда я попытался отфильтровать набор данных, я получил это:

Исключение из первого шанса на $7594845D. Исключительный класс EAccessViolation с сообщением "Нарушение прав доступа по адресу 4DB1E8D1 в модуле" midas.dll ". Прочитать адрес 00FC0298'.

Протестированный код:

procedure TForm1.FormCreate(Sender: TObject);
var
  S: string;
  FieldDef: TFieldDef;
  MemTable: TClientDataSet;
begin
  S := 'Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ';

  MemTable := TClientDataSet.Create(nil);
  try
    FieldDef := MemTable.FieldDefs.AddFieldDef;
    FieldDef.DataType := ftWideString;
    FieldDef.Size := 255;
    FieldDef.Name := 'MyField';

    MemTable.CreateDataSet;
    MemTable.Append;
    MemTable.FieldByName('MyField').AsWideString := S;
    MemTable.Post;

    ShowMessage(MemTable.FieldByName('MyField').AsWideString); { ← data lost }
    MemTable.Filter := '[MyField] LIKE ' + QuotedStr('%' + 'ǰűmpεď' + '%');
    MemTable.Filtered := True; { ← access violation }
    ShowMessage(MemTable.FieldByName('MyField').AsWideString);
  finally
    MemTable.Free;
  end;
end;

Я надеюсь, что это не связано с вашей версией Delphi, но, тем не менее, я бы предпочел использовать FireDAC, если вы можете. Там вы бы сделали то же самое для строк Unicode (ваш код изменился бы, заменив TClientDataSet на TFDMemTable и добавив модули FireDAC).

Другие вопросы по тегам