wtorek, 30 listopada 2010

translate

Jeżeli robimy dużo zmian w tekście używając funkcji REPLACE dochodzimy do momentu w którym edycja jest możliwa wyłącznie przy odpowiednim formatowaniu kodu.
Przykładem jest funkcja konwertująca stronę kodową Mazovia (CP620) a stroną Windows-1250 napisaną przez Pawła Potasińskiego.

CREATE FUNCTION dbo.ufn_MazoviaTo1250 (@String varchar(maX))
RETURNS varchar(max)
WITH SCHEMABINDING
AS
BEGIN
  SET @String = @String COLLATE Polish_BIN;
  RETURN
    REPLACE (
      REPLACE (
        REPLACE (
          REPLACE (
            REPLACE (
              REPLACE (
                REPLACE (
                  REPLACE (
                    REPLACE (
                      REPLACE (
                        REPLACE (
                          REPLACE (
                            REPLACE (
                              REPLACE (
                                REPLACE (
                                  REPLACE (
                                    REPLACE (
                                      REPLACE (
                                        @String, CHAR(165), CHAR(209) -- Ñ
                                      ), CHAR(143), CHAR(165)         -- ¥
                                    ), CHAR(163), CHAR(211)           -- Ó
                                  ), CHAR(156), CHAR(163)             -- £
                                ), CHAR(149), CHAR(198)               -- Æ
                              ), CHAR(144), CHAR(202)                 -- Ê
                            ), CHAR(152), CHAR(140)                   -- Œ
                          ), CHAR(160), CHAR(143)                     -- 
                        ), CHAR(161), CHAR(175)                       -- ¯
                      ), CHAR(134), CHAR(185)                         -- ¹
                    ), CHAR(141), CHAR(230)                           -- æ
                  ), CHAR(145), CHAR(234)                             -- ê
                ), CHAR(146), CHAR(179)                               -- ³
              ), CHAR(164), CHAR(241)                                 -- ñ
            ), CHAR(162), CHAR(243)                                   -- ó
          ), CHAR(158), CHAR(156)                                     -- œ
        ), CHAR(166), CHAR(159)                                       -- Ÿ
      ), CHAR(167), CHAR(191)                                         -- ¿
    ) COLLATE database_default;
END;

Wygląda nieźle ale jakby trzeba było zamienić więcej niż 100 znaków?

Można zrobić coś takiego, żeby było łatwiej tworzymy tabelę mapowania

CREATE TABLE mapa (id INT IDENTITY(1,1), map VARCHAR(256), rep NVARCHAR(256))
go
Dodajemy do niej wartości kodu ascii

INSERT mapa (map,rep)
VALUES (165,209)
 , (143 , 165)
 , (163 , 211)
 , (156 , 163)
 , (149 , 198)
 , (144 , 202)
 , (152 , 140)
 , (160 , 143)
 , (161 , 175)
 , (134 , 185)
 , (141 , 230)
 , (145 , 234)
 , (146 , 179)
 , (164 , 241)
 , (162 , 243)
 , (158 , 156)
 , (166 , 159)
 , (167 , 191)
 go

I robimy funkcję

create function dbo.translate(@txt nvarchar(max))
returns nvarchar(max)
as
begin
SET @txt =@txt COLLATE Polish_BIN
select @txt = replace(@txt, CHAR(map), CHAR(rep))
from mapa
  return @txt;
end
go

metody tej możemy użyc również do zamieniania dowolnych ciągów znakowych w tekście, należy zmodyfikować funkcję

alter function dbo.translate(@txt nvarchar(max))
returns nvarchar(max)
as
begin
select @txt = replace(@txt, map, rep)
from mapa
  return @txt
end
go

zmieniamy dane do mapowania

DELETE FROM mapa
go
INSERT mapa (map,rep)
VALUES (1,'jeden*')
 , (2 , 'dwa*')
 , (3 , 'trzy*')          
 , (4 , 'cztery*')          
 , (5, 'pięć*')          
 , (6 , 'sześć*')                
 , (7 , 'siedem*')                
 , (8 , 'osiem*')                
 , (9 , 'dziewięć*')                      
 , (0 , 'zero*')                       
 go

testujemy

SELECT dbo.translate ('167870349076');

3 komentarze:

  1. Jakiekolwiek dywagacje na temat udoskonalania funkcji T-SQLa z "REPLACE" nie mają sensu. Są za wolne!

    Jedyne słuszne rozwiązanie to funkcja CLR.
    Tylko bez żadnych regexp-ów.
    Same REPLACE - sprawdzone i przetestowane.

    Taka CLR-owa funkcja działa 10 razy szybciej.

    Polecam.

    pozdr
    GREGOR

    OdpowiedzUsuń
  2. mam pewne obawy czy uda się napisać CLR który będzie szybszy przy próbce wynoszącej 10 - 20 obiektów. CLR dużo dłużej się inicjują i żeby pokazały swoje możliwości próbka musi mieć parę set rekordów.

    OdpowiedzUsuń
  3. @GREGOR: Samo Replace nie daje chyba wyboru co do rozróżniania wielkich i małych liter (co na pewno umożliwiają RegExpy). A REPLACE w T-SQL działa z uwzględnieniem collation.

    OdpowiedzUsuń