views:

120

answers:

2

I use this function to read file to string

function LoadFile(const FileName: TFileName): string;
begin
  with TFileStream.Create(FileName,
      fmOpenRead or fmShareDenyWrite) do begin
    try
      SetLength(Result, Size);
      Read(Pointer(Result)^, Size);
    except
      Result := '';  
      Free;
      raise;
    end;
    Free;
  end;
end;

Here's the text of file :

version  

Here's the return value of LoadFile :

'ÿþv'#0'e'#0'r'#0's'#0'i'#0'o'#0'n'#0

I want to make a new file contain "verabc". The problem is I still have a problem to replace "sion" with "abc". I am using D2007. If I remove all #0 then the result become Chinese character.

A: 

It seems that you load a unicode encoded text file. 0 indicates Latin character.

If you don't want to deal with unicode text, choose ANSI encoding in your editor when you save the file.

If you need unicode encoding, use WideCharToString to convert it to an ANSI string, or just remove yourself the 0s, though the latter isn't the best solution. Also remove the 2 leading characters, ÿþ.
The editor put those bytes to mark the file as unicode.

Nick D
0 indicates English language? Which value indicates Klingon language? :)
mjustin
@Cosmin, thanks, I edited my answer.
Nick D
0 indicates Latin? Si tacuisses ... :)
mjustin
+8  A: 

What you think is the text of the file isn't really the text of the file. What you've read into your string variable is accurate. You have a Unicode text file encoded as little-endian UTF-16. The first two bytes represent the byte-order mark, and each pair of bytes after that are another character of the string.

If you're reading a Unicode file, you should use a Unicode data type, such as WideString. You'll want to divide the file size by two when setting the length of the string, and you'll want to discard the first two bytes.

If you don't know what kind of file you're reading, then you need to read the first two or three bytes first. If the first two bytes are $ff $fe, as above, then you might have a little-endian UTF-16 file; read the rest of the file into a WideString, or UnicodeString if you have that type. If they're $fe $ff, then it might be big-endian; read the remainder of the file into a WideString and then swap the order of each pair of bytes. If the first two bytes are $ef $bb, then check the third byte. If it's $bf, then they are probably the UTF-8 byte-order mark. Discard all three and read the rest of the file into an AnsiString or an array of bytes, and then use a function like UTF8Decode to convert it into a WideString.

Once you have your data in a WideString, the debugger will show that it contains version, and you should have no trouble using a Unicode-enabled version of StringReplace to do your replacement.

Rob Kennedy
ah sorry, there's some trouble with my editor. I open the file with notepad and everything goes well!!.
Evidently, the default encoding in Vista UTF-16. It's about time. If you really need a different encoding, use the "save as" dialog box and choose something different. Everything goes well when you open the file in Notepad because it uses the procedure I described in my answer. It's even a little more involved than that, since it considers ANSI encoding, too.
Rob Kennedy