Omvandla text i UTF-8 till standard ANSI


Idag hade jag tänkt visa en funktion som omvandlar text kodat i UTF-8 till vanlig ANSI, så att det går att spara utan förlust i SQL Server. Nu har SQL Server 2012 stöd för UTF-8 men inte alla har investerat i SQL Server 2012 ännu.

Wikipedia har denna förklaring till vad UTF-8 är (http://sv.wikipedia.org/wiki/UTF8):

UTF-8 (åtta-bitars Unicode transformationsformat) är en längdvarierande teckenkodning som används för att representera text kodad i Unicode, som en sekvens av byte (oktetter). Unicode använder upp till 21 bitar per tecken, vilket inte får plats i en byte, och därför används till exempel i textfiler vanligen en av metoderna UTF-8 eller UTF-16 för att få en serie bytes. UTF-8 har valts som huvudsaklig teckenkodning i internetprotokoll: nya protokoll måste stöda denna teckenkodning, om det inte av speciella skäl är olämpligt.

För inte så länge sedan hade jag en kund som ville spara ner svar från webbformulär ner i deras databas. Då den externa samarbetspartnern använde UTF-8 visade det sig snabbt ohanterbart att låta tecken försvinna i databasen för att kunna lagra informationen.

För att få en så snabb kod som möjligt tittade jag på problemet i den andra änden, dvs vilka ansikoder har en motsvarighet i UTF-8 och inte tvärtom. Det visade sig ganska snabbt att det bara är 0x60 koder som har en motsvarighet och det är alla koder för ANSI 0xA0 och upp till och med 0xFF. Alla dessa koder har ett prefix i UTF-8 som antingen är 0xC2 eller 0xC3.

Med detta i minne började jag skriva en iterativ skalär funktion. Jag vet att det inte är det optimala men i detta fallet är en skalär funktion det mest användbara.


CREATE
FUNCTION dbo.fnConvertUtf8Ansi
(
    @Source VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
    DECLARE @Value SMALLINT = 160,
            @Utf8 CHAR(2),
            @Ansi CHAR(1)

    IF @Source NOT LIKE ‘%[ÂÃ]%’
        RETURN  @Source

    WHILE @Value <= 255
        BEGIN
            SELECT  @Utf8 = CASE
                                WHEN @Value BETWEEN 160 AND 191 THEN CHAR(194) + CHAR(@Value)
                                WHEN @Value BETWEEN 192 AND 255 THEN CHAR(195) + CHAR(@Value 64)
                                ELSE NULL
                            END,
                    @Ansi = CHAR(@Value)

            WHILE CHARINDEX(@Source, @Utf8) > 0
                SET    @Source = REPLACE(@Source, @Utf8, @Ansi)

            SET    @Value += 1
        END

    RETURN  @Source
END

Vad funktionen gör är att för alla koder i ansi som har en motsvarighet, ta fram motsvarigeten i UTF-8 och göra en replace på bara dessa koder om de verkligen finns i texten.

Have any Question or Comment?

Leave a Reply