HotXLS her BIFF8 AutoFilter ölçütünü iki 10 baytlık DOPER yapısı taşıyan bir AUTOFILTER kaydına yazar ve DOPER türü Excel'in nasıl karşılaştıracağına karar verir. v2.384.45'ten bu yana TXLSWorksheet.ApplyAutoFilter, '>=100' gibi bir karşılaştırmayı IEEE sayı DOPER'ı olarak yazıyor; böylece Excel metin karşılaştırmak yerine sayısal hücreleri eşleştiriyor. Değişikliği tetikleyen hata raporu kısaydı ve sinir bozucuydu: gecelik bir dışa aktarma tutar sütununa filtre uyguladı, dosya hiç ses çıkarmadan açıldı, açılır ok ölçütü gösterdi ve filtre sıfır satırla eşleşti. Bozuk bir şey yoktu. Baytlar geçerli BIFF8'di, sadece yanlış türden geçerliydi; bu makale tam da bu tür bir başarısızlığı, v2.384.18'de düzeltilen iki eski bayt düzeyi hatayla birlikte ele alıyor
BIFF8 AutoFilter aslında neyi saklar?
Bir BIFF8 AutoFilter tek kayıt değil üç kayıt türünden oluşur ve ölçütleri yalnızca alan başına kayıt taşır. AUTOFILTERINFO ($009D, [MS-XLS] §2.4.8) filtre aralığının kaç sütun kapsadığını yazar. FILTERMODE ($009B) gövdesiz bir işarettir ve HotXLS bunu en az bir alanın etkin ölçütü olduğunda yayar. Ardından her etkin alan kendi AUTOFILTER kaydını alır ($009E, §2.4.6): 0 tabanlı bir alan indeksi, düşük iki biti wJoin olan bir grbit sözcüğü, tam 10'ar baytlık iki DOPER ve varsa string DOPER'ın karakterlerini taşıyan isteğe bağlı bir kuyruk. Alan indeksi diskte 0 tabanlıdır; oysa ApplyAutoFilter alanları 1'den numaralar, bu da ilk kez bir kaydı hex dökümünde ararken işinize yarar. Her DOPER'ın ilk baytı olan vt, ardından ne tür bir işlenen geldiğini söyler:
$04, kalan 8 baytta saklanan bir IEEE 754 double'dır; Excel sayısal karşılaştırmayı böyle saklar$06, uzunluğu tek bircchbaytında yaşayan bir dizedir; karakterlerin kendisi kayıt kuyruğuna itilir$08bir Bes değeridir, yani iki bayta paketlenmiş bir Boolean ya da hata kodu$0Cve$0Eişlenen taşımaz; boş olanların tümüyle eşleş ve boş olmayanların tümüyle eşleş demektir
İkinci bayt olan grbitSgn karşılaştırmayı taşır: 1'den 6'ya kadar sırasıyla <, =, <=, >, <> ve >='ye karşılık gelir. HotXLS her iki baytı da işlemden sonra AutoFilterColumns üzerinden görünür kılar; bu koleksiyonun ögeleri Criteria1 ve Criteria2'yi, DataType, grbitSgn ve Value taşıyan TXLSAutofilterDOPER nesneleri olarak açar; böylece yazılacak olanı tahmin etmek yerine assert ile doğrulayabilirsiniz
'>=100' filtresi Excel'de neden hiçbir satırla eşleşmedi?
Filtrenin hiçbir şeyle eşleşmemesinin nedeni, işlenenin metin olarak saklanmış olması ve Excel'in string DOPER'ı hücreyle metin olarak karşılaştırmasıydı. v2.384.45 öncesinde lxFilter.pas içindeki CreateFilterDoper >= önekini doğru şekilde söküyor ve işareti 6'ya ayarlıyor, ardından her zaman 100 karakterlerini taşıyan bir vtString DOPER kuruyordu. 250 tutan bir sayı hücresi, "100" ile yapılan metin karşılaştırmasını asla sağlamaz; böylece her satır elendi. İstisna yok, tanı yok, Excel'den onarım istemi yok. v2.384.45'ten beri kural bilinçli biçimde dardır: ölçüt bir karşılaştırma operatörüyle başlıyorsa ve kalanı invariant-culture kurallarına göre sayı olarak ayrıştırılıyorsa HotXLS aynı işaretle bir vtIEEENumber DOPER yazar. Operatörsüz çıplak bir değer string biçiminde kalır; çünkü Excel de açılır listeden seçilen bir ögeyi böyle saklar
var
Wb: IXLSWorkbook;
Sh: TXLSWorksheet;
Doper: TXLSAutofilterDOPER;
begin
Wb := TXLSWorkbook.Create;
Sh := Wb.Sheets.Add;
Sh.Cells[1, 1].Value := 'Region';
Sh.Cells[1, 2].Value := 'Amount';
Sh.Cells[2, 1].Value := 'North';
Sh.Cells[2, 2].Value := 250;
// Alan 2 = A1:B100 aralığının ikinci sütunu (API tarafında 1 tabanlı)
Sh.ApplyAutoFilter('A1:B100', 2, '>=100');
Doper := Sh.AutoFilterColumns.Find(2).Criteria1;
// v2.384.45+: DataType = 4 (IEEE sayı), grbitSgn = 6 (>=)
// Düzeltmeden önce: DataType = 6 (string), hiçbir şeyle eşleşmiyordu
Assert(Doper.DataType = 4);
Wb.SaveAs('orders.xls');
end;
Keskin kalan kenarlar ayrıştırmada yaşıyor. İşlenen, ondalık ayırıcı olarak nokta ile TryStrToFloat'tan geçer; böylece '>=1.5' sayı olur, '>=1,5' ise string DOPER olarak kalır ve Windows yerel ayarı ne derse desin yine sessizce hiçbir şeyle eşleşmez. Tarihler aynı tuzağın farklı bir kostümüdür: '>=2026-01-01' bir sayı değildir, bu yüzden metin olarak yazılır; oysa Excel tarih hücrelerini seri numaraları olarak tutar. Bir sayıda eşitlik için '=100' de 100 gibi sayısal bir Variant de IEEE DOPER üretir (işaret 2); çıplak '100' dizesi ise bir metin eşleşmesi üretir. Sayısal işlenenleri insanlar için biçimlendirmek yerine kodda kurun:
var
Fmt: TFormatSettings;
Since: TDateTime;
begin
Fmt := TFormatSettings.Create;
Fmt.DecimalSeparator := '.';
// Kesirli eşik: her zaman nokta ile biçimlendir
Sh.ApplyAutoFilter('A1:D500', 3, '>' + FloatToStr(1499.5, Fmt));
// Tarihler: Excel'in hücrede sakladığı seri numarasıyla karşılaştır.
// Mart 1900 sonrası tarihler için Delphi TDateTime, 1900 sistemi serine eşittir
Since := EncodeDate(2026, 1, 1);
Sh.AutoFilterColumns.SetFieldCriteria(4, '>=' + IntToStr(Trunc(Since)),
xlAnd, Unassigned);
end;
AND ve OR iki koşulu nasıl birleştirir?
AUTOFILTER grbit'inin wJoin bitleri AND için 0, OR için 1'dir ve HotXLS bu iki sabiti v2.384.18'e kadar ters tutuyordu. En az 100 ve 500 altı gibi bir between tarzı filtre, en az 100 ya da 500 altı olarak kaydediliyordu; bu da pratikte her sayıyla eşleşir ve filtrenin hiç uygulanmamış görünmesine yol açar. Genel operatör sabitleri ikinci bir taşıma tuzağı ekler. HotXLS'te xlAnd 0, xlOr 1'dir; Excel otomasyonu ise onları 1 ve 2 olarak numaralar. XlAutoFilterOperator düz bir Byte'dır, dolayısıyla VBA makrosundan literal sayılarla çevrilen kod sorunsuz derlenir ve COM'da AND anlamına gelen literal 1 burada OR olur. Adlandırılmış sabitleri kullanın; sorun o zaman ortaya çıkamaz:
// Tutar 100 (dahil) ile 500 (hariç) arasında
Sh.ApplyAutoFilter('A1:D500', 3, '>=100', xlAnd, '<500');
with Sh.AutoFilterColumns.Find(3) do
begin
Assert(Operator = xlAnd); // diskte wJoin = 0
Assert(Criteria2.grbitSgn = 1); // 1 = küçüktür
end;
Boolean'lar, boşluklar ve 255 karakter üst sınırı
Bir Boolean ölçütü Bes değeri olarak saklanır ([MS-XLS] §2.5.10) ve Bes, değer baytı bBoolErr'ü önce, fError bayrağını sonra koyar. HotXLS v2.384.18 öncesinde ikisini ters sırada yazıyordu; TRUE için bir filtre 1'i hata bayrağına koyuyor ve Excel ölçütü bir hata kodu olarak okuyordu. Yazıcı ve okuyucu birlikte tersine çevrilmişti; HotXLS kendi dosyalarını hiç ses çıkmadan gidiş dönüşlü işlerken Excel'in katılmamasının nedeni buydu ve kendi kendine tutarlı bir gidiş dönüşün spesifikasyon uyumu hakkında hiçbir şey kanıtlamadığını hatırlatır. Boşlukların hiç işlenene ihtiyacı yoktur: tek başına '=' geçmek tüm boşluklarla eşleş DOPER'ını ($0C), tek başına '<>' ise tüm boş olmayanlarla eşleş DOPER'ını ($0E) üretir
String ölçütleri DOPER yerleşiminde katı bir üst sınıra çarpar. cch uzunluk alanı tek bayttır; bir string işleneni 255 karakteri aşamaz ve CreateFilterDoper uzunluk baytının taşıp kayıt kuyruğunu desensronize etmesine izin vermek yerine operatörü söktükten sonra daha uzun metni kırpar. Kırpma sessizdir ve uzun açıklama sütunundaki bir filtre, geçirdiğiniz tam metinden farklı eşleşebilir. BIFF8'de kuyruk her dizeyi tek baytlık bir bayrak ve ardından gelen UTF-16 kod birimleri olarak saklar ve bildirilen kayıt boyutu o baytları tam olarak saymalıdır; aynı kayıt tutma disiplini BIFF kayıt uzunluğu bildirimlerinin bir Delphi XLS yazıcısında nasıl kaydığı makalesinde ele alınıyor
İkinci ApplyAutoFilter çağrısı ilkini neden siler?
Her ApplyAutoFilter çağrısı tüm filtre aralığını yeniden tanımlar; bu yüzden yalnızca son çağrının ölçütü hayatta kalır. Dahili olarak aralığı yeniden kurmadan önce her alanı temizleyen SetAutoFilter'ı çağırır; bu tek sütun için doğru, iki sütun için şaşırtıcıdır. Birkaç sütunu filtrelemek için ApplyAutoFilter'ı aralığı ve ilk ölçütü kurmak üzere bir kez çağırın, sonra diğerlerini aralığa ve öteki alanlara dokunmayan AutoFilterColumns.SetFieldCriteria üzerinden ekleyin. Her iki yol da aralık dışındaki bir alan numarasını istisna fırlatmadan yok sayar; o yüzden geri okuyarak doğrulayın, ideali kaydedilen dosyayı yeniden açtıktan sonra:
Sh.ApplyAutoFilter('A1:D500', 1, 'North'); // aralık + alan 1
Sh.AutoFilterColumns.SetFieldCriteria(3, '>=100', xlAnd, Unassigned);
Sh.AutoFilterColumns.SetFieldCriteria(4, True, xlAnd, Unassigned);
Wb.SaveAs('orders.xls');
Wb := TXLSWorkbook.Create;
Wb.Open('orders.xls');
Assert(Wb.Sheets[1].AutoFilterColumns.Find(1).Active);
Assert(Wb.Sheets[1].AutoFilterColumns.Find(3).Criteria1.DataType = 4);
Şunu akılda tutun: AUTOFILTER kaydı saklanmış bir tanımdır; HotXLS ölçütleri yazar ama klasik XLS çalışma sayfasında onları değerlendirmez, dolayısıyla eşleşen satırlara sunucuda ihtiyaç duyan bir hattın onları orada kendisinin hesaplaması gerekir; XLSX yüzü ise HotXLS veri doğrulama, AutoFilter ve Delphi'de tablolar makalesinde gösterildiği gibi satır düzeyinde değerlendirme sunar. Excel satırları bir kez gizlediğinde, aralığın altındaki toplamlar SUBTOTAL ve AGGREGATE'in gizlenmiş ve filtrelenmiş satırlara nasıl davrandığına bağlıdır; sessizce hiçbir şeyle eşleşen sayısal bir filtrenin yanlış sayı olarak ortaya çıktığı bir sonraki yer de orasıdır
HotXLS, Excel'in beklendiği gibi değerlendirdiği sayısal, Boolean ve AND/OR DOPER'lı AutoFilter ölçütleri dahil olmak üzere BIFF8 XLS ve XLSX çalışma kitaplarını Delphi ve C++Builder'dan yerel olarak okur ve yazar. Özellikler, sürümler ve deneme indirmesi için HotXLS Delphi elektronik tablo bileşenine bakın