Dzisiaj mam jedynie mały trick na który natrafiłem a który uważam za sprytne rozwiązania problemu. Nawet nie wiedziałem, że coś takiego jest możliwe w elixir. Nie przyszło mi do głowy, żeby spróbować coś podobnego zrobić a… da się.
Problem/rozwiązanie: jak zrobić substring w Elixir?
W elixir nie ma czegoś takiego jak substring jaki znamy chociażby z JavaScript czy też C#. Więc niby taka prosta rzecz może wydawać się skomplikowana choć taka nie jest. Ale by zrozumieć, jak to działa, musimy poznać operator zakresu.
W elixir mamy coś takiego jak operator zakresu (range) którym są dwie kropki: ..
, możemy to wykorzystać w różny sposób, na przykład:
range = 10..100 start..end = range
Gdzie start
to 10
a end
to 100
. Operator zakresu deklaruje więc nam listę liczb. Dodatkowo jak widać na powyższym przypadku jest możliwość wykonania na nim pattern matching i pobrania stanu początkowego i końcowego. Taki zakres możemy przekonwertować do listy dzięki metodzie Enum.to_list/1
która zwróci nam listę liczb zaczynając od 10
i idącą aż do 100
ze skokiem co jeden: 10, 11, 12 .. 100
.
Dodatni zakres jest dość zrozumiały – tworzymy kolejne liczby i tyle. Ale już stworzenie zakresu ujemnego 0..-4
nie przyszło mi nigdy do głowy a przecież to nic innego jak zakres liczb od 0
do -4
-> 0
, -1
, -2
, -3
i -4
. nie wiem czemu zakładałem, że to jest po prostu niemożliwe. Byłem w błędzie :)
Wracając do naszego substring, elixir posiada metody String.slice/2
oraz String.slice/3
które umożliwiają nam to samo co substring. Metoda String.slice/3 jest standardową metodą przyjmując ciąg znaków, początek i długość – nic nadzwyczajnego, więc to pominę.
Zaś metoda String.slice/2
przyjmuje jako drugi parametr zakres, który może wyglądać tak:
String.slice "gutek", 1..-1
Co to zrobi? Zwróci nam to utek
a dokładnie mówiąc zwróci nam wynik działania wzięcia substring od indeksu 1
do końca słowa.
String.slice "gutek", 1..-2
Już zwróci nam ute
– i g
i k
zostaną ucięte. Jeżeli nie interesuje nas ucinanie końcówki to możemy wykonać polecenie bez minusów:
String.slice "gutek", 1..2
Które zwróci ut
.
Tak jaka przy dodatnich zakresach sprawa jest dość jasna: weź znak z miejsca START
i weź tylko END
znaków. Tak przy minusie to zaczyna być trochę bardziej skomplikowane na tyle że sam nie mogę jakoś tego rozsądnie dobrać w słowa. Ale można powiedzieć, weź znak z miejsca START
i następne aż do END
znaku od końca. Czyli przy -1
to będzie do k
, przy -2
to e
, przy -3
do t
itd.
Jeżeli zaś jako START
podamy ujemny indeks, to tak jakbyśmy zaczynali od znaku START
od końca (czyli jak podamy -2
to będzie to e
) i następnie znów możemy podać albo ujemną liczbę albo dodatnią jako END
. Przy dodatniej, to tak jakbyśmy liczyli od lewej strony:
String.slice "gutek", -2..1 "" String.slice "gutek", -2..3 "e" String.slice "gutek", -2..4 "ek"
Przy ujemnym END
po prostu liczymy od prawej strony:
String.slice "gutek", -2..-3 "" String.slice "gutek", -2..-2 "e" String.slice "gutek", -2..-1 "ek"
Zrozumiałe? Mi trochę zrozumienie tych wartości minusowych zajęło ;(
Ale zarazem fajna i ciekawa opcja robienia substring.
PS.: slice
dlatego, że w końcu ciągi znaków to lista znaków… ;)