22/07/2012

Jeden dziwny znak, a kilka rzeczy do zapamiętania

Home

Niedawno zetknąłem się z raportem, który wypluwał dane do pliku. Przy czym jednym z wymagań było aby trim'ować pola, które zostały dopełnione do wymaganej długości. W tym celu użyto funkcji rtrim. Przeglądając wyprodukowane raporty, zauważyłem jednak, że w niektórych przypadkach zawartość jednego pola zawiera jakieś białe znaki. Na pierszy rzut oka wyglądało to na spacje. Na wszelki wypadek sprawdziłem czy napewno zastosowano rtrim i wszystko się zgadzało.

Rozpocząłem więc poszukiwania czemu rtrim mogło nie zadziałać i od razu nauczyłem się pierwszej rzeczy, do której nie przywiązywałem wcześniej uwagi. rtrim obsługuje tylko spacje i nie poradzi sobie z tabulatorem, znakiem powrotu karetki itd. Poniżej krótki przykład demonstrujący problem (char(9) to tabulator).

DECLARE @string char(10)
SET @string = 'abc' + char(9)

SELECT LEN(@string), LEN(RTRIM(@string))

Rozwiązaniem problemu może być na przykład użycie funckji replace:

SELECT LEN(@string), LEN(RTRIM(@string)), LEN(REPLACE(@string,char(9),SPACE(0)))

W tym przypadku to jednak nie pomogło. W pliku wyjściowym cały czas pojawiały się te "dziwne" spacje. Użyłem więc prostego skryptu aby zobaczyć kody znaków dla pola, które sprawiało problemy. Okazało się, że te dziwne "spacje" to znak o kodzie 255. Teraz w zależności od tego do jakiej tablicy znaków zajrzałem uzyskałem inną informację. Na przykład według ISO 8859-1 to znak łacińska mała litera Y z diarezą/umlautem.

Tutaj dochodzimy do kolejnej ważnej rzeczy, którą łatwo przeoczyć kiedy przez większość czasu pracujemy w dobrze określonym środowisku z takimi, a nie innymi ustawieniami regionalnymi itd. Otóż ten sam znak może wyglądać inaczej kiedy wykonamy zapytanie w Microsoft SQL Server Management Studio ze względu na collation, a inaczej po zapisaniu do pliku i otwarciu w jakimś edytorze ze względu na wybraną w programie stronę kodową itd. Poniższy skrypt pokazuje jak ten sam znak zostanie zaprezentowany dla różnych collation.

DECLARE @string char(10)
SET @string = 'abc' + char(255)
SELECT @string
Collate SQL_Latin1_General_CP1_CI_AS
SELECT @string
Collate SQL_Polish_CP1250_CI_AS

Nie ma w tym nic trudnego i przez większość czasu kwestie kodowania, tablicy znaków... nas nie obchodzą ale warto pamiętać o takich rzeczach bo potem mogą pojawić się cokolwiek zaskakujący efekty, nie zawsze oczywiste do wyjaśnienia.

Post ten dotyczy MSSQL 2008.

2 comments:

Anonymous said...

Ciekawe. A jak w końcu pozbyłeś się teg znaku o kodzie 255? Replacem?

Michał Komorowski said...

Jak już zorientowałem się co to za znak to doszedłem do wniosku, że nie ma sensu z tym walczyć. Przecież ktoś go kiedyś musiał go wprowadzić, z powietrza się nie wziął. Można się z tym spierać ale skoro dodałbym kod obsługujący znak o kodzie 255, to czemu nie dodać kodu obsługującego inne "dziwne" znaki. Moim zdaniem mija się to z celem. W większości wypadków i tak będziemy mieli do czynienia tylko ze standardowymi znakami.

Post a Comment