Dopo alcuni esperimenti, ho terminato con il seguente codice per eseguire la ricerca e la sostituzione in MSWord. Questo codice funziona perfettamente anche nell'intestazione e nel piè di pagina, inclusi i casi in cui l'intestazione e/o il piè di pagina sono diversi per la prima pagina o per le pagine pari/dispari.Migliorare le prestazioni della ricerca Sostituisci nel documento Word utilizzando OLE e Delphi
Il problema è che ho bisogno di chiamare MSWordSearchAndReplaceInAllDocumentParts
per ogni stringa che sostituisco, e ottengo prestazioni inaccettabili (2 minuti per circa 50 stringhe in una parola doc di 4 pagine). Idealmente dovrebbe essere "istantaneo", ovviamente.
Prima di gestire intestazioni e piè di pagina stavo semplicemente cercando e sostituisco nel documento principale (usando wdSeekMainDocument). In quel caso la perforazione era accettabile (anche se abbastanza lenta). Mi chiedo solo perché è così lento: la commutazione della visualizzazione richiede tempo? In genere le intestazioni o i piè di pagina contengono poche parole, quindi mi aspettavo che tutte le intestazioni e i piè di pagina Cerca e Sostituisci non stessero peggiorando le prestazioni complessive. Ma questo non è quello che ho osservato.
Questo è il codice, in fondo ho messo risultati profiler:
// global variable (just for convenience of posting to Stack Overflow)
var
aWordApp: OLEVariant; // global
// This is the function that is executed once per every string I replace
function MSWordSearchAndReplaceInAllDocumentParts;
begin
try
iseekValue := aWordApp.ActiveWindow.ActivePane.View.SeekView;
iViewType := aWordApp.ActiveWindow.ActivePane.View.Type;
if iViewType <> wdPrintView then
aWordApp.ActiveWindow.ActivePane.View.Type := wdPrintView;
if aWordApp.ActiveDocument.PageSetup.OddAndEvenPagesHeaderFooter then
begin
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekEvenPagesFooter;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekEvenPagesHeader;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
end;
if aWordApp.ActiveDocument.PageSetup.DifferentFirstPageHeaderFooter then
begin
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekFirstPageFooter;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekFirstPageHeader;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
end;
//Replace in Main Docpart
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekMainDocument;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
//Replace in Header
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekCurrentPageHeader;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
//Replace in Footer
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekCurrentPageFooter;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
//Replace in Header
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekPrimaryHeader;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
//Replace in Footer
Try
aWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekPrimaryFooter;
SearchAndReplaceInADocumentPart;
Except
// do nothing ..it was not able to set above view
end;
finally
aWordApp.ActiveWindow.ActivePane.View.SeekView := iseekValue;
if iViewType <> wdPrintView then
aWordApp.ActiveWindow.ActivePane.View.Type := iViewType;
end;
end;
// This is the function that performs Search And Replace in the selected View
// it is called once per view
function SearchAndReplaceInADocumentPart;
begin
aWordApp.Selection.Find.ClearFormatting;
aWordApp.Selection.Find.Text := aSearchString;
aWordApp.Selection.Find.Replacement.Text := aReplaceString;
aWordApp.Selection.Find.Forward := True;
aWordApp.Selection.Find.MatchAllWordForms := False;
aWordApp.Selection.Find.MatchCase := True;
aWordApp.Selection.Find.MatchWildcards := False;
aWordApp.Selection.Find.MatchSoundsLike := False;
aWordApp.Selection.Find.MatchWholeWord := False;
aWordApp.Selection.Find.MatchFuzzy := False;
aWordApp.Selection.Find.Wrap := wdFindContinue;
aWordApp.Selection.Find.Format := False;
{ Perform the search}
aWordApp.Selection.Find.Execute(Replace := wdReplaceAll);
end;
Qui incollo risultati profiling (ho AQTime pro):
Can you please help me a individuare la problema?
SE hai davvero bisogno di prestazioni POI usare Word tramite OLE/ActiveX non è fondamentalmente intenzione di tagliarlo ... sta usando una libreria (senza dipendenza da Word) per gestire i documenti di Word un'opzione? – Yahia
Sarebbe meglio se fosse possibile fornire un documento di esempio appropriato per il benchmarking. – menjaraz
Puoi approfondire i risultati del profilo: è il tempo in secondi o millisecondi, è il tempo per colpo o il cumulativo di tutti i colpi? –