ANSI to UTF8

teo teo.ubuntu at yahoo.com
Thu Feb 3 06:26:13 PST 2011


On Mon, 31 Jan 2011 17:08:33 +0000, Janusch wrote:

> Hello!
> 
> I'm trying to convert ANSI characters to UTF8 that but it doesn't work
> correctly.
> 
> I used the following:
> 
> void main() {
> 	writeln(convertToUTF8("ä"));
> }
> 
> string convertToUTF8(string text) {
> 
> 	string result;
> 
> 	for (uint i=0; i<text.length; i++) {
> 		char ch = text[i];
> 		if (ch < 0x80) {
> 			result ~= ch;
> 		} else {
> 			result ~= 0xC0 | (ch >> 6);
> 			result ~= 0x80 | (ch & 0x3F);
> 		}
> 	}
> 	return result;
> 
> }
> 
> But writeln doesn't print anything (only a blank line), but not my
> character. The same problem exists for similar characters like ü or ö.
> 
> Is there anything I'm doing wrong?


You may give a try to the following code. It is based on PHP 5.2.9
---
module ISO88591;

/+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++
decode latin-1 (ISO-8859-1) string to UTF-8
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++/
string decode(byte[] content)
{
	byte[] result = new byte[content.length * 4];
	uint n = 0;
	uint i = content.length;
	ubyte* p = cast(ubyte*)content.ptr;
	while (i > 0)
	{
		uint c = cast(uint)*p;
		if (c < 0x80)
		{
			result[n++] = cast(ubyte)c;
		}
		else if (c < 0x800)
		{
			result[n++] = cast(ubyte)(0xC0 | (c >> 6));
			result[n++] = cast(ubyte)(0x80 | (c & 0x3F));
		}
		else if (c < 0x10000)
		{
			result[n++] = cast(ubyte)(0xE0 | (c >> 12));
			result[n++] = cast(ubyte)(0xC0 | ((c >> 6) & 
0x3F));
			result[n++] = cast(ubyte)(0x80 | (c & 0x3F));
		}
		else if (c < 0x200000)
		{
			result[n++] = cast(ubyte)(0xF0 | (c >> 18));
			result[n++] = cast(ubyte)(0xE0 | ((c >> 12) & 
0x3F));
			result[n++] = cast(ubyte)(0xC0 | ((c >> 6) & 
0x3F));
			result[n++] = cast(ubyte)(0x80 | (c & 0x3F));
		}
		p++;
		i--;
	}
	result.length = n;
	return cast(string)result;
}

/+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++
encode UTF-8 string to latin-1 (ISO-8859-1)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++/
byte[] encode(string content)
{
	byte[] buf = cast(byte[])content;
	byte[] result = new byte[buf.length];
	uint n = 0;
	uint i = buf.length;
	ubyte* p = cast(ubyte*)buf.ptr;
	while (i > 0)
	{
		uint c = *p;
		if (c >= 0xF0)
		{
			// four bytes encoded, 21 bits
			if (i >= 4)
			{
				c = ((p[0] & 0x07) << 18) | ((p[1] & 
0x3F) << 12) | ((p[2] & 0x3F) << 6) | (p[3] & 0x3F);
			}
			else
			{
				c = 0x3F;
			}
			p += 4;
			i -= 4;
		}
		else if (c >= 0xE0)
		{
			// three bytes encoded, 16 bits
			if (i >= 3)
			{
				c = ((p[0] & 0x3F) << 12) | ((p[1] & 
0x3F) << 6) | (p[2] & 0x3F);
			}
			else
			{
				c = 0x3F;
			}
			p += 3;
			i -= 3;
		}
		else if (c >= 0xC0)
		{
			// two bytes encoded, 11 bits
			if (i >= 2)
			{
				c = ((p[0] & 0x3F) << 6) | (p[1] & 0x3F);
			}
			else
			{
				c = 0x3F;
			}
			p += 2;
			i -= 2;
		}
		else
		{
			p++;
			i--;
		}
		// use '?' (0x3F) if no mapping is possible
		result[n++] = cast(ubyte)((c > 0xFF) ? 0x3F : c);
	}
	result.length = n;
	return result;
}
---

I wrote it for D1 and did now quick tests with D2. It should be working.
Please give feedback.

And here is my test program:

import std.stdio;
import ISO88591;

void main()
{
	string str = "äöüß";
	auto tmp = encode(str);
	writefln("latin-1:%x", cast(ubyte[])tmp);
	auto res = decode(tmp);
	writefln("utf-8:%x:%s", cast(ubyte[])res, res);

	return;
}


More information about the Digitalmars-d-learn mailing list