Как я могу отфильтровать строковое поле в наборе данных с помощью предложения 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).