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:
- Weź tekst
- Znajdź w nim podwójną spację.
- 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ą.
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
powinno być
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).
Dzięki za czujność – poprawione.