0
Public Function UTF8FromUTF16(ByRef abytUTF16() As Byte) As Byte() 

    Dim lngByteNum As Long 
    Dim abytUTF8() As Byte 
    Dim lngCharCount As Long 

    On Error GoTo ConversionErr 

    lngCharCount = (UBound(abytUTF16) + 1) \ 2 
    lngByteNum = WideCharToMultiByteArray(CP_UTF8, 0, abytUTF16(0), _
        lngCharCount, 0, 0, 0, 0) 

    If lngByteNum > 0 Then  
        ReDim abytUTF8(lngByteNum - 1) 
        lngByteNum = WideCharToMultiByteArray(CP_UTF8, 0, abytUTF16(0), _
            lngCharCount, abytUTF8(0), lngByteNum, 0, 0) 
        UTF8FromUTF16 = abytUTF8 
    End If 

    Exit Function 

ConversionErr:
    MsgBox " Conversion failed " 

End Function 

var 
    abytUTF8 : array of Byte; // Global

function UTF8FromUTF16(sUTF16 : WideString) : pAnsiChar; 
var 
    lngByteNum : integer; 
    lngCharCount : integer; 
begin 
    // On Error GoTo ConversionErr 
    result := nil; 

    lngCharCount := Length(sUTF16); 
    lngByteNum := WideCharToMultiByte(CP_UTF8, 0, @sUTF16[1],
        lngCharCount, nil, 0, nil, nil); 

    If lngByteNum > 0 Then 
    begin 
        SetLength(abytUTF8, lngByteNum+1); 
        abytUTF8[lngByteNum] := 0; 
        lngByteNum := WideCharToMultiByte(CP_UTF8, 0, @sUTF16[1],
            lngCharCount, @abytUTF8[0], lngByteNum, nil, nil); 
        result := pAnsiChar(@abytUTF8[0]); 
    End; 
End; 
Martin G
  • 17,357
  • 9
  • 82
  • 98
user1390537
  • 15
  • 2
  • 4
  • Similar: http://stackoverflow.com/questions/259836/what-is-the-best-way-to-convert-tbytes-utf-16-to-a-string – Harriv May 12 '12 at 06:53
  • While I sympathize with your predicament, you should at least **attempt** to explain what your problem is. In its current form, the question is of no use to anyone else, and it is too much to expect other people to read it and try to guess what your problem is. (And in trying to express yourself in English, you will improve your English skills ... which you need to do if you are going to ask questions here in the future.) – Stephen C May 13 '12 at 08:06

2 Answers2

5

Your code does not set encoding of the resulting string. Delphi (since Delphi 2009) requires encoding info for ANSI string, otherwise default system locale used. A working version of your code is:

function UTF8FromUTF16(sUTF16: UnicodeString): UTF8String;
var
  lngByteNum : integer;
  lngCharCount : integer;
begin
  Result := '';

  lngCharCount := Length(sUTF16);
  if lngCharCount = 0 then Exit;

  lngByteNum := WideCharToMultiByte(CP_UTF8, 0, @sUTF16[1], lngCharCount, nil, 0, nil, nil);
  if lngByteNum > 0 then begin
    SetLength(Result, lngByteNum);
    WideCharToMultiByte(CP_UTF8, 0, @sUTF16[1], lngCharCount, @Result[1], lngByteNum, nil, nil);
  end;
end;

But you need not that all - Delphi performs string conversions for you:

function UTF8FromUTF16_2(sUTF16: UnicodeString): UTF8String;
begin
  Result := sUTF16;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
kludg
  • 27,213
  • 5
  • 67
  • 118
  • Yes, UTF16 is UTF16-LE in both functions. If you need UTF16-BE use `TEncoding` class from `SysUtils.pas`. – kludg May 12 '12 at 10:59
1

A literal translation would look like this:

function UTF8FromUTF16(const abytUTF16: TBytes): TBytes;
var
  lngByteNum: LongInt;
  abytUTF8: TBytes;
  lngCharCount: LongInt;
begin
  Result := nil;
  lngCharCount := Length(abytUTF16) div 2;
  lngByteNum := WideCharToMultiByte(CP_UTF8, 0, PWideChar(abytUTF16), lngCharCount, nil, 0, nil, nil); 
  if lngByteNum > 0 then
  begin
    SetLength(abytUTF8, lngByteNum);
    lngByteNum := WideCharToMultiByte(CP_UTF8, 0, PWideChar(abytUTF16), lngCharCount, PAnsiChar(abytUTF8), lngByteNum, nil, nil);
    Result := abytUTF8;
    Exit;
  end;
  if GetLastError <> 0 then
    MessageBox(0, ' Conversion failed ', '', MB_OK);
end;

In Delphi 2009+, there is a much simplier approach:

function UTF8FromUTF16(const abytUTF16: TBytes): TBytes;
begin
  Result := TEncoding.Convert(TEncoding.Unicode, TEncoding.UTF8, abytUTF16);
end;

Even easier, if you work with strings instead of bytes, then you can simply assign a WideString or a UnicodeString (both of which are UTF-16 encoded) to a UTF8String and let the RTL handle the conversion for you.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • How to use function.? UTF8FromUTF16('Some Text'); < Error – user1390537 May 13 '12 at 07:46
  • The original VB code was based on byte arrays, not strings. If you want to use strings instead, then you don't need any of this code. As I said, simple use Delphi's `UnicodeString` and `UTF8String` types instead, and let the 3(" handle the conversion, eg: `var sUtf16: UnicodeString; sUtf8: UTF8String; begin sUtf16 := 'Some Text'; sUtf8 := sUtf16; end;` – Remy Lebeau May 13 '12 at 16:12