2015-07-27 3 views
1

Я использую Lazarus для создания простого приложения, которое строит подписи Outlook на основе шаблона. Идея состоит в том, чтобы извлечь шаблон (ZIP-файл) и заменить переменные в файлах, которые он содержит.Lazarus: StringReplace неэффективен при работе с файлами (проблема с unicode)

Например, я могу заменить {fullname} на имя, предоставленное пользователем.

В настоящее время я использую реализацию ниже, но это кажется неэффективным. Файл читается и записывается, но, похоже, замены не выполняются. Я проверил, не работает ли моя реализация TFileStream, но с помощью WriteAnsiString для добавления фиктивного текста в конец выходного файла.

Прошу вас, пожалуйста, взглянуть на мой код ниже и сообщить мне, что я, возможно, сделал не так, или если есть какие-то лучшие альтернативы StringReplace? Я знаю, что можно использовать TStringList, но при этом прерывается окончание строк. В качестве заметок и расширенных изменений используется TStringList, использование которых тоже не поможет.

Update:

Я видел this, но с использованием AnsiString не имеет никакого значения. Если я не ошибаюсь, FPC использует его по умолчанию в любом случае, а не UnicodeString.

Update 2:

Действительно, AnsiString по умолчанию. Использование строки unicode (что делает работу с заменой) добавляет ? в начало и конец файла. Зачем это делать?


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; 

Использование:

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

Ваш файл шаблона содержит текст UTF16? Если да - попробуйте перекодировать его в UTF8 (собственное кодирование для Lazarus). – Abelisto

+0

Похоже, что файл '.txt', создаваемый Outlook Outlook, действительно UTF-16LE (в то время как файл' .htm' - это Windows-1252). Как я могу кодировать кодировку соответствующего файла и преобразовывать соответственно? –

+1

О перекодировке текста вы можете прочитать здесь [здесь] (http://wiki.lazarus.freepascal.org/Multiplatform_Programming_Guide#Text_encoding). Однако для моего маленького тестового файла в UTF-16LE функция 'GuessEncoding' возвращает' utf8' по неизвестной причине.Использование кодирования с жестким кодированием отлично работает: 'ShowMessage (ConvertEncoding (s, EncodingUCS2LE, EncodingUTF8));' Не забудьте использовать блок LConvEncoding. – Abelisto

ответ

1

Благодаря комментарий Abelisto в выше, то возникает вопрос в связи с тем, что внешний вид сохраняет три файла он создает с различными кодировками. Чтобы обойти это, я просто использовал convertEncoding и guessEncoding от lconvencoding, как показано ниже:

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

encodingAnsi, как представляется, является лучшим преобразования, по крайней мере в моем случае. Преобразование в UTF8 (с или без спецификации) вызвало некоторую головную боль с определенными символами, в частности EmDash или EnDash.

 Смежные вопросы

  • Нет связанных вопросов^_^