Lazarus:处理文件时 StringReplace 无效(unicode 问题)
Lazarus: StringReplace ineffective when working with files (unicode issue)
我正在使用 Lazarus 构建一个基于模板构建 Outlook 签名的简单应用程序。这个想法是提取模板(一个 ZIP 文件),并替换它包含的文件中的变量。
例如,我可能想用用户提供的名称替换{fullname}
。
我目前正在使用下面的实现,但似乎没有效果。该文件已读取和写入,但似乎没有进行替换。我已经测试过我的 TFileStream
实现是否不正确,但是使用 WriteAnsiString
将虚拟文本附加到输出文件的末尾是可行的。
请您看看我下面的代码,让我知道我可能做错了什么,或者是否有比 StringReplace
更好的替代方法?我知道可以使用 TStringList
- 但是,这样做会破坏行尾。由于备忘录和丰富的编辑使用 TStringList
,使用它们也无济于事。
更新:
我看过this,但使用AnsiString
没有区别。如果我没记错的话,反正FPC默认是用的,而不是UnicodeString
.
更新二:
确实,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']);
感谢 Abelisto 上面的评论,问题似乎是因为 Outlook 保存了它使用不同编码创建的三个文件。为了解决这个问题,我简单地使用了 lconvencoding
中的 convertEncoding
和 guessEncoding
,如下所示:
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(有或没有 BOM)导致某些字符有点头疼,特别是 EmDash 或 EnDash。
我正在使用 Lazarus 构建一个基于模板构建 Outlook 签名的简单应用程序。这个想法是提取模板(一个 ZIP 文件),并替换它包含的文件中的变量。
例如,我可能想用用户提供的名称替换{fullname}
。
我目前正在使用下面的实现,但似乎没有效果。该文件已读取和写入,但似乎没有进行替换。我已经测试过我的 TFileStream
实现是否不正确,但是使用 WriteAnsiString
将虚拟文本附加到输出文件的末尾是可行的。
请您看看我下面的代码,让我知道我可能做错了什么,或者是否有比 StringReplace
更好的替代方法?我知道可以使用 TStringList
- 但是,这样做会破坏行尾。由于备忘录和丰富的编辑使用 TStringList
,使用它们也无济于事。
更新:
我看过this,但使用AnsiString
没有区别。如果我没记错的话,反正FPC默认是用的,而不是UnicodeString
.
更新二:
确实,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']);
感谢 Abelisto 上面的评论,问题似乎是因为 Outlook 保存了它使用不同编码创建的三个文件。为了解决这个问题,我简单地使用了 lconvencoding
中的 convertEncoding
和 guessEncoding
,如下所示:
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(有或没有 BOM)导致某些字符有点头疼,特别是 EmDash 或 EnDash。