Τεχνικό Άρθρο

Σύγκριση δύο βιβλίων εργασίας Excel στη Delphi με το HotXLS

Το HotXLS συγκρίνει δύο βιβλία εργασίας μέσω της TXLSXWorkbookCompare, η οποία αντιστοιχίζει φύλλα εργασίας κατά όνομα, διασχίζει τα γεμάτα κελιά κάθε ζεύγους, και αναφέρει τι διαφέρει ως δομημένη λίστα εγγραφών διαφοράς και, εφόσον ζητηθεί, ως μία αναγνώσιμη γραμμή ανά διαφορά. Δεν εμπλέκεται καμία εγκατάσταση Excel, και η σύγκριση εκτελείται εξ ολοκλήρου πάνω στο φορτωμένο μοντέλο αντικειμένων στη Delphi ή στο C++Builder

Η ανάγκη συνήθως εμφανίζεται την πρώτη φορά που κάποιος ρωτά τι άλλαξε. Ένα βιβλίο εργασίας οικονομικών επιστρέφει από αναθεώρηση, μια νυχτερινή εξαγωγή αναδημιουργείται μετά από αλλαγή κώδικα, ή δύο τμήματα στέλνουν εκδόσεις του ίδιου προτύπου. Το άνοιγμα και των δύο δίπλα-δίπλα λειτουργεί για ένα φύλλο και αποτυγχάνει για είκοσι. Η σύγκριση αρχείων byte προς byte δεν απαντά τίποτα, επειδή δύο αποθηκεύσεις του ίδιου βιβλίου εργασίας διαφέρουν με τρόπους που δεν ενδιαφέρουν κανέναν

Τι μετράει ως διαφορά;

Η σύγκριση αναφέρει οκτώ είδη, και το σύνολο είναι σκόπιμα μικρό: φύλλο προστέθηκε ή αφαιρέθηκε, γεμάτο κελί προστέθηκε ή αφαιρέθηκε, κελί του οποίου η τιμή άλλαξε, κελί του οποίου ο τύπος άλλαξε, και συγχωνευμένο εύρος προστέθηκε ή αφαιρέθηκε. Όλα εκφράζονται σε σχέση με το αριστερό βιβλίο εργασίας ως τη γραμμή βάσης, οπότε ένα προστιθέμενο στοιχείο υπάρχει μόνο στα δεξιά και ένα αφαιρούμενο στοιχείο μόνο στα αριστερά

Τα φύλλα αντιστοιχίζονται κατά όνομα και όχι κατά θέση. Η αναδιάταξη φύλλων εργασίας επομένως δεν παράγει καμία διαφορά, κάτι που είναι σχεδόν πάντα η συμπεριφορά που θέλετε: ένας χρήστης που σέρνει μια καρτέλα δεν είναι αλλαγή δεδομένων. Ένα φύλλο που υπάρχει μόνο στη μία πλευρά αναφέρει μία καταχώριση επιπέδου φύλλου αντί να επεκτείνει κάθε γεμάτο κελί μέσα του, κάτι που κρατά αναγνώσιμη μια αναφορά δύο δομικά διαφορετικών βιβλίων εργασίας αντί να γίνεται χιλιάδες γραμμές μακριά

Τιμή ή τύπος, και πώς συγκρίνεται καθένα

Κάθε κελί συνεισφέρει μια υπογραφή, και ο κανόνας είναι απλός: ένα κελί που φέρει τύπο συγκρίνεται με το κείμενο του τύπου με πρόθεμα σύμβολο ίσον, και ένα κελί χωρίς τύπο συγκρίνεται με την τιμή του μετατρεπόμενη σε κείμενο. Αυτή η διάκριση έχει μεγαλύτερη σημασία απ' όσο φαίνεται αρχικά. Δύο κελιά μπορούν να κρατούν τον ίδιο εμφανιζόμενο αριθμό ενώ το ένα είναι κυριολεκτικό και το άλλο τύπος, και η αντιμετώπισή τους ως ίσα θα έκρυβε ακριβώς την επεξεργασία που αξίζει περισσότερο να εντοπιστεί σε ένα αναθεωρημένο βιβλίο εργασίας

Σημαίνει επίσης ότι ένας τύπος του οποίου το κείμενο είναι αμετάβλητο δεν αναφέρει διαφορά ακόμη κι αν το προσωρινά αποθηκευμένο αποτέλεσμά του διαφέρει, που είναι η σωστή συμπεριφορά για σύγκριση συγγεγραμμένου περιεχομένου, και η λάθος συμπεριφορά αν προσπαθείτε να εντοπίσετε μετατόπιση επανυπολογισμού. Για εκείνο το δεύτερο ερώτημα, επανυπολογίστε και τα δύο βιβλία εργασίας πριν τη σύγκριση, ώστε οι τιμές που συγκρίνετε να είναι αυτές που οι τύποι πραγματικά παράγουν σήμερα

Εκτέλεση μιας σύγκρισης

Η Compare δέχεται τα δύο φορτωμένα βιβλία εργασίας και επιστρέφει τον αριθμό διαφορών που βρέθηκαν. Η λίστα διαφορών είναι έπειτα διαθέσιμη κατά ευρετήριο, ή μπορεί να αδειάσει σε οποιοδήποτε TStrings:

uses
  lxHandleX, lxCompare;

var
  Left, Right: TXLSXWorkbook;
  Cmp: TXLSXWorkbookCompare;
  Lines: TStringList;
begin
  Left := TXLSXWorkbook.Create;
  Right := TXLSXWorkbook.Create;
  Cmp := TXLSXWorkbookCompare.Create;
  Lines := TStringList.Create;
  try
    if (Left.Open('baseline.xlsx') <> 1) or
       (Right.Open('reviewed.xlsx') <> 1) then
      Exit;

    if Cmp.Compare(Left, Right) = 0 then
      Writeln('workbooks are equivalent')
    else
    begin
      Cmp.Report(Lines);              // μία αναγνώσιμη γραμμή ανά διαφορά
      Lines.SaveToFile('workbook-diff.txt');
      Writeln(Format('%d difference(s) written', [Cmp.Count]));
    end;
  finally
    Lines.Free;
    Cmp.Free;
    Right.Free;
    Left.Free;
  end;
end;

Μια γραμμή που παράγεται από την Report διαβάζεται όπως value changed: Data!A2: 10 -> 99, κάτι που είναι αρκετό για έναν αναθεωρητή και αρκετό για μήνυμα commit. Αυτή είναι η επιφάνεια που βλέπει ο άνθρωπος. Η προγραμματιστική επιφάνεια είναι η ίδια η εγγραφή διαφοράς, και είναι αυτή που πρέπει να χρησιμοποιήσετε όταν η σύγκριση τροφοδοτεί μια απόφαση αντί για ένα έγγραφο

Οδήγηση λογικής από τις δομημένες διαφορές

Κάθε διαφορά εκθέτει το είδος της, το όνομα φύλλου, γραμμή και στήλη βασισμένες στο ένα για καταχωρίσεις επιπέδου κελιού, μια αναφορά A1 για καταχωρίσεις επιπέδου συγχώνευσης, και το αριστερό και δεξί κείμενο. Καταχωρίσεις επιπέδου φύλλου και επιπέδου συγχώνευσης αναφέρουν γραμμή και στήλη ως μηδέν, που είναι ο τρόπος να τις ξεχωρίσετε χωρίς να επιθεωρήσετε το είδος:

var
  I: Integer;
  D: TlxCompareDiff;
  FormulaEdits: Integer;
begin
  FormulaEdits := 0;
  for I := 0 to Cmp.Count - 1 do
  begin
    D := Cmp.Diff(I);
    case D.Kind of
      lckFormulaChanged:
        begin
          Inc(FormulaEdits);
          Writeln(Format('%s R%dC%d: %s => %s',
            [D.Sheet, D.Row, D.Col, D.LeftText, D.RightText]));
        end;
      lckSheetAdded, lckSheetRemoved:
        Writeln(Format('structure: %s', [D.Describe]));
      lckMergeAdded, lckMergeRemoved:
        Writeln(Format('layout: %s at %s', [D.Describe, D.Ref]));
    end;
  end;

  // Πολιτική αναθεώρησης που μπλοκάρει μόνο σε επεξεργασίες τύπων
  if FormulaEdits > 0 then
    raise Exception.CreateFmt(
      '%d formula change(s) need sign-off', [FormulaEdits]);
end;

Δύο ιδιότητες της εξόδου αξίζει να τις γνωρίζετε πριν γράψετε ισχυρισμούς εναντίον της. Η σειρά των καταχωρίσεων επιπέδου κελιού ακολουθεί την εσωτερική σειρά διάσχισης του αποθηκευτικού χώρου κελιών, οπότε οι δοκιμές πρέπει να γράφονται ανεξάρτητα από τη σειρά. Και η υπογραφή τύπου φέρει το δικό της πρόθεμα σύμβολο ίσον, που σημαίνει ότι μια περιγραφική συμβολοσειρά χτισμένη με συνένωση μπορεί να εμφανίσει διπλό ==· ελέγξτε τις τιμές πεδίων αντί να αναλύετε την περιγραφική γραμμή όταν το αποτέλεσμα οδηγεί λογική

Πού αποδίδει η σύγκριση βιβλίων εργασίας

Τρεις χρήσεις δικαιολογούν το χαρακτηριστικό από μόνες τους. Δοκιμή οπισθοδρόμησης μιας μηχανής αναφορών: κρατήστε ένα γνωστά σωστό βιβλίο εργασίας, αναδημιουργήστε, συγκρίνετε, και αποτύχετε την κατασκευή σε οποιαδήποτε απρόσμενη διαφορά. Αναθεώρηση αλλαγών: δώστε σε έναν αναθεωρητή την αναγνώσιμη αναφορά αντί για δύο αρχεία. Και επαλήθευση μετάπτωσης: μετά τη μετατροπή μιας παρτίδας παλαιότερων βιβλίων εργασίας, συγκρίνετε κάθε αποτέλεσμα με την πηγή του για να αποδείξετε ότι τίποτα δεν χάθηκε

Εκείνη η τρίτη περίπτωση συνδυάζεται φυσικά με τα περάσματα απογραφής και ελέγχου που περιγράφονται στον πάγκο εργασίας ελέγχου και μετατροπής βιβλίων εργασίας, όπου η καταμέτρηση του τι περιέχει ένα βιβλίο εργασίας γίνεται πριν τη μετατροπή και η σύγκριση γίνεται μετά. Αν οι διαφορές σας συγκεντρώνονται γύρω από εισαγόμενες γραμμές, οι κανόνες αναγραφής αναφορών στον προσαρμογή αναφορών τύπων σε εισαγωγή και διαγραφή εξηγούν γιατί τύποι που φαίνονται αμετάβλητοι αναφέρονται ως αλλαγμένοι

Τα όρια, δηλωμένα ξεκάθαρα

Η σύγκριση καλύπτει τιμές, τύπους, συγχωνεύσεις και παρουσία φύλλων. Δεν συγκρίνει μορφές αριθμών, γραμματοσειρές, γεμίσματα, κανόνες υπό όρους μορφοποίησης, επικυρώσεις δεδομένων, γραφήματα, εικόνες ή ορισμένα ονόματα. Ένα κελί του οποίου η τιμή είναι πανομοιότυπη αλλά η μορφή άλλαξε από Γενική σε Νόμισμα δεν αναφέρει διαφορά, κάτι που είναι σωστό για σύγκριση δεδομένων και ανεπαρκές για αναθεώρηση μορφοποίησης

Κελιά με τιμές ημερομηνίας αξίζουν μία συγκεκριμένη προειδοποίηση: συγκρίνονται ως η μετατροπή τους σε κείμενο, οπότε ένα βιβλίο εργασίας αποθηκευμένο στο σύστημα ημερομηνίας 1904 και ένα στο σύστημα 1900 μπορούν να συγκριθούν ως ίσα ή άνισα με τρόπους που σας εκπλήσσουν αν οι υποκείμενοι σειριακοί αριθμοί διαφέρουν. Οι κανόνες συστήματος ημερομηνίας καλύπτονται στους σειριακούς αριθμούς ημερομηνίας και το σύστημα 1904. Όταν η μορφοποίηση ή η πιστότητα σε επίπεδο αντικειμένου αποτελεί μέρος της ερώτησης, συνδυάστε τη σύγκριση με ένα πέρασμα ελέγχου που καταμετρά αυτά τα χαρακτηριστικά σε κάθε πλευρά

Η σύγκριση, ο έλεγχος και η μετατροπή βιβλίων εργασίας εκτελούνται όλα στην ίδια μηχανή για Delphi και C++Builder· η πλήρης λίστα χαρακτηριστικών βρίσκεται στη σελίδα του εξαρτήματος υπολογιστικών φύλλων HotXLS για Delphi