2015-07-27 2 views
1

J'utilise Lazarus pour créer une application simple qui construit des signatures Outlook basées sur un modèle. L'idée est d'extraire le modèle (un fichier ZIP) et de remplacer les variables dans les fichiers qu'il contient.Lazarus: StringReplace inefficace lorsque vous travaillez avec des fichiers (problème unicode)

Par exemple, je souhaite remplacer {fullname} par le nom fourni par l'utilisateur. J'utilise actuellement l'implémentation ci-dessous, mais elle semble inefficace. Le fichier est lu et écrit, mais il semble que les remplacements ne sont pas faits. J'ai testé pour voir si ma mise en œuvre de TFileStream n'est pas correcte, mais en utilisant WriteAnsiString pour ajouter du texte factice sur la fin du fichier de sortie fonctionne.

S'il vous plaît veuillez regarder mon code ci-dessous et laissez-moi savoir ce que j'ai pu faire de mal, ou s'il y a de meilleures alternatives à StringReplace? Je suis conscient que l'on peut utiliser TStringList - cependant, cela casse les fins de ligne. Comme les mémos et les éditions riches utilisent TStringList, l'utilisation de ceux-ci n'aidera pas non plus.

Mise à jour:

J'ai vu this, mais en utilisant AnsiString ne fait aucune différence. Si je ne me trompe pas, FPC l'utilise par défaut de toute façon, au lieu de UnicodeString.

Mise à jour 2:

En effet, AnsiString est la valeur par défaut. L'utilisation d'une chaîne unicode (qui fait fonctionner les remplacements) ajoute ? au début et à la fin du fichier. Pourquoi ferait-il ça?


function multiStringReplace(const s: string; search, replace : array of string; flags : tReplaceFlags): string; 
var c : cardinal; 
begin 
    assert(length(search) = length(replace), 'Array lengths differ.'); 
    result := s; 
    for c := low(search) to high(search) do 
     result := stringReplace(result, search[c], replace[c], flags); 
end; 
procedure fileReplaceString(const fileName: string; search, replace: array of string); 
var 
    fs: tFileStream; 
    s: string; 
begin 
    fs := tFileStream.create(fileName, fmOpenRead or fmShareDenyNone); 
    try 
     setLength(s, fs.size); 
     fs.readBuffer(s[1], fs.size); 
    finally 
     fs.free(); 
    end; 
    s := multiStringReplace(s, search, replace, [rfReplaceAll, rfIgnoreCase]); 
    fs := tFileStream.create(fileName, fmOpenWrite); 
    try 
     fs.writeBuffer(s[1], length(s)); 
    finally 
     fs.free(); 
    end; 
end; 

Utilisation:

fileReplaceString(currentFile, ['{fullname}'], ['Full Name']); 
+0

Votre fichier modèle contient-il du texte UTF16? Si oui, essayez de le recoder en UTF8 (codage natif pour Lazarus). – Abelisto

+0

Il semble que le fichier '.txt' généré par Outlook soit en fait UTF-16LE (alors que le fichier' .htm' est Windows-1252). Comment puis-je choisir l'encodage du fichier en question et le convertir en conséquence? –

+1

A propos du transcodage de texte, vous pouvez lire [ici] (http://wiki.lazarus.freepascal.org/Multiplatform_Programming_Guide#Text_encoding) par exemple. Cependant, pour mon petit fichier de test dans la fonction UTF-16LE, 'GuessEncoding' renvoie' utf8' pour une raison inconnue.L'utilisation du codage source codé en dur fonctionne bien: 'ShowMessage (ConvertEncoding (s, EncodingUCS2LE, EncodingUTF8));' Ne pas oublier d'utiliser l'unité 'LConvEncoding'. – Abelisto

Répondre

1

Merci au commentaire de Abelisto ci-dessus, il semble que la question est due au fait que Outlook enregistre les trois fichiers qu'il crée avec des encodages différents. Pour contourner le problème, j'ai simplement utilisé convertEncoding et guessEncoding de lconvencoding, comme ci-dessous:

uses 
    lconvencoding; 
// Read string 
s := convertEncoding(
    multiStringReplace(s, search, replace, [rfReplaceAll, rfIgnoreCase]), 
    guessEncoding(s), encodingAnsi 
); 
// Write modified and converted string back to file 

encodingAnsi semble être la meilleure conversion, au moins dans mon cas. La conversion en UTF8 (avec ou sans nomenclature) a causé un peu de mal de tête avec certains caractères, en particulier EmDash ou EnDash.