Pchełki SQL, odcinek 13: despacjizacja stringulacji, czyli usuwamy wielokrotne spacje z tekstu

https://xpil.eu/PCJ1Y

Od paru dni na blogu posucha. Rok szkolny uderzył w nas jak obuchem, trzeba się przeorganizować, znów przyzwyczaić do wcześniejszego wstawania, prac domowych, opanować kalendarz zajęć dodatkowych, to wszystko pochłania znaczne ilości czasu.

Dziś jednak udało mi się wygrzebać chwilę na tę krótką pchełkę.

Pchełka jest o tyle ciekawa, że prezentuje nietypowe rozwiązanie bardzo typowego i starego jak komputery problemu: jak w elegancki, szybki i wydajny sposób zastąpić wielokrotne spacje w tekście spacją pojedynczą?

Załóżmy, że mamy taki tekst: Jaś                  i                                Małgosia
Chcemy z niego zrobić taki tekst: Jaś i Małgosia

Najbardziej odruchowe podejście większości Braci Programujących będzie następujące:

  1. Weź tekst
  2. Znajdź w nim podwójną spację.
  3. Jeżeli się udało, wstaw w miejsce znalezionej podwójnej spacji spację pojedynczą i przejdź do poprzedniego kroku. A jeżeli się nie udało, voila, finito, skończone!

Metoda, oczywiście, jest jak najbardziej poprawna. Po pięciu, może sześciu iteracjach dostaniemy tekst bez wielokrotnych spacji.

Gdybyśmy chcieli to zapisać w SQL, moglibyśmy zrobić na przykład w taki sposób:

DECLARE @strTekst VARCHAR(MAX) = 'Jaś               i                               Małgosia';
WITH q1 AS (
 SELECT 1 AS n, @strTekst AS t
 UNION ALL
 SELECT n + 1, REPLACE(t, '  ', ' ') 
 FROM q1
 WHERE n < 20 AND CHARINDEX('  ', t) > 0)
 SELECT TOP 1 t FROM q1 ORDER BY n DESC;

Albo w taki:

DECLARE @strTekst VARCHAR(MAX) = 'Jaś              i                             Małgosia';

WHILE CHARINDEX('  ', @strTekst) > 0
SET @strTekst = REPLACE(@strTekst, '  ', ' ')

SELECT @strTekst;

To są jednak, jak już nadmieniłem, metody "nieeleganckie", w takim sensie, że wymagają pętli (mniej lub bardziej ukrytej, ale zawsze).

Chcę dziś pokazać metodę o wiele bardziej elegancką, nie wymagającą żadnych dodatkowych operatorów oprócz REPLACE, działającą na dowolnej ilości spacji, ale przede wszystkim odświeżająco nietypową i nie wymagającą żadnej pętli.

Oczywiście ktoś mógłby się przyczepić, że operator REPLACE sam w sobie jest pętlą, ale kłócąc się w ten sposób dojdziemy do wniosku, że jest nią również obsługa kursora myszy.

Kod wygląda tak:

DECLARE @strTekst VARCHAR(MAX) = 'Jaś               i                              Małgosia';

SELECT REPLACE(REPLACE(REPLACE(@strTekst, ' ', '{}'), '}{', ''), '{}',' ')

Pomysł jest pozornie banalny, jednak wymaga dość specyficznego sposobu myślenia. Zazdroszczę autorowi (kod ten znalazłem w Sieci) nietypowego podejścia oraz umiejętności napoczynania problemu od dupy strony. Co tu się właściwie dzieje?

Mamy zagnieżdżone trzy operatory REPLACE().

Ten najbardziej wewnętrzny zamienia wszystkie spacje (nieważne, pojedyncze czy wielokrotne) na parę znaków: {}

Wynik tego wewnętrznego REPLACE jest taki:

Jaś{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}i{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}Małgosia

Środkowy REPLACE zamienia wszystkie wystąpienia ciągu "}{" na ciąg pusty, w efekcie otrzymujemy:

Jaś{}i{}Małgosia

Wreszcie ostatni REPLACE zamienia "{}" na pojedyncze spacje, w wyniku czego dostajemy:

Jaś i Małgosia

Jedyne niebezpieczeństwo takiego podejścia jest takie, że wybierając znaki "{" oraz "}" musimy mieć absolutną pewność, że ich kombinacja (czyli "{}" lub "}{") nie występuje nigdzie w zamienianym przez nas tekście. Jeżeli takiej pewności nie mamy, musimy zdecydować się na inną parę znaków lub powrócić do metody z pętlą.

https://xpil.eu/PCJ1Y

2 komentarze

  1. Hej.
    Ten sposób z 3 REPLACE’ami – SUPER ! 😉
    W tych 2 wcześniejszych sposobach (z WITH i WHILE) wkradł się błąd… Tam gdzie jest weryfikacja warunku

    CHARINDEX(' ', @strTekst) > 0
    

    powinno być

    CHARINDEX('  ', @strTekst) > 0
    

    O ile w pierwszym przykładzie (WITH) ten warunek “nie szkodzi” (ale też nie pomaga 🙂 a co do zasady miał pomagać) o tyle w drugim powoduje “pętlę nieskończoną” (o ile oczywiście w zmienianym tekście jest choćby 1 spacja).

Leave a Comment

Komentarze mile widziane.

Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]

Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.