User Professor Hans Noodles
Professor Hans Noodles
Poziom 41

Metoda String.split() w Javie: dzielenie stringów na części

Opublikowano w grupie Poland
Porozmawiajmy o metodzie String.split Javy: do czego służy i dlaczego jest potrzebna. Nietrudno się domyślić, że dzieli ciąg znaków w Javie, ale jak to działa w praktyce? Zanurzmy się głębiej w działanie metody i omówmy kilka nieoczywistych szczegółów. W tym samym czasie dowiemy się, ile metod split (dzielenia) faktycznie posiada String. To do dzieła!Metoda String.split() w Javie: dzielenie stringów na części - 1

Opis i sygnatura String.split w Javie (Java split)

split w Java to metoda, która dzieli ciąg na podciągi przy użyciu separatora zdefiniowanego za pomocą wyrażenia regularnego. Przedstawmy zatem sygnaturę metody i rozpocznijmy nasze nurkowanie:

String[] split(String regex)
Z sygnatury jasno wynikają dwie rzeczy:
  1. Metoda zwraca tablicę ciągów.
  2. Metoda posiada parametr ciągu wejściowego o nazwie regex.
Przeanalizujmy każdą z nich osobno, rozkładając powyższy opis na czynniki pierwsze.
  1. Metoda zwraca tablicę ciągów.

    Deklaracja zawiera następujące słowa: „W Javie metoda split dzieli ciąg na podciągi.” Metoda zbiera te podciągi do tablicy, która staje się zwracaną wartością.

  2. Metoda posiada parametr ciągu wejściowego o nazwie regex.

    Następnie przypomnij sobie opis: „dzieli ciąg na podciągi przy użyciu separatora zdefiniowanego za pomocą wyrażenia regularnego”. Parametr wejściowy regex to wyrażenie regularne zastosowane na oryginalnym ciągu. Gdy znak lub kombinacja znaków pasują do siebie, traktowane są jako separator.

Podział w Javie - praktyka

A teraz przejdźmy do sedna. Wyobraźmy sobie, że mamy ciąg słów. Jak na przykład tutaj:
Uwielbiam Javę
Musimy podzielić ciąg na słowa. Widzimy, że słowa w tym ciągu oddzielone są od siebie spacjami. W tym przypadku znak spacji jest idealnym kandydatem na nasz separator. Kod do rozwiązania naszego zadania wyglądałby następująco:

public class Main {
    public static void main(String[] args) {
        String str = "Uwielbiam Javę";
        String[] words = str.split(" ");
        for (String word : words) {
            System.out.println(word);
        }
    }
}
Wyjściem metody main będą następujące wiersze:
Uwielbiam Javę
Zobaczmy jeszcze kilka przykładów działania metody split:
String Separator Wynik działania metody
"Uwielbiam Javę" " " (znak spacji) {"Uwielbiam", "Javę"}
"192.168.0.1:8080" ":" {"192.168.0.1", "8080"}
"Czerwony, pomarańczowy, żółty" "," {"Czerwony", " pomarańczowy", " żółty"}
"Czerwony, pomarańczowy, żółty" ", " {"Czerwony", "pomarańczowy", "żółty"}
Zwróć uwagę na różnice pomiędzy dwoma ostatnimi wierszami w powyższej tabeli. W przedostatnim wierszu jako separator użyty został przecinek. W rezultacie, gdy ciąg jest podzielony, niektóre słowa mają początkowe spacje. W ostatnim wierszu jako separatora użyliśmy przecinka i spacji. Dlatego w wynikowej tablicy nie było podciągów z początkowymi spacjami. To tylko drobny szczegół, który pokazuje, jak ważne jest staranne wybranie odpowiedniego separatora.

Główny separator

Jest to kolejny ważny niuans. Jeśli oryginalny ciąg zaczyna się od separatora, to pierwszy element tablicy wynikowej będzie pustym ciągiem. Na przykład, wyglądałoby to tak: Oryginalny ciąg: " Uwielbiam Javę" Separator: " " Otrzymana tablica: {"", "Uwielbiam", "Javę" } Ale jeśli oryginalny ciąg kończy się separatorem, a nie zaczyna, to wynik będzie inny: Oryginalny ciąg: "Uwielbiam Javę " Separator: " " Otrzymana tablica: { "Uwielbiam", "Javę" } Spójrz na kod i zobacz, jak działanie metody split różni się z symbolem separatora na końcu i/lub na początku oryginalnego ciągu:

public class Main {
    public static void main(String[] args) {
        print("Uwielbiam Javę".split(" "));
        print(" Uwielbiam Javę".split(" "));
        print("Uwielbiam Javę ".split(" "));
        print(" Uwielbiam Javę ".split(" "));
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}
Wynik metody main będzie wyglądał następująco:
[Uwielbiam, Javę] [, Uwielbiam, Javę] [Uwielbiam, Javę] [, Uwielbiam, Javę]
Ponownie zwróć uwagę na fakt, że jeśli pierwszy znak w oryginalnym ciągu jest znakiem separatora, to w rezultacie pierwszy element tablicy będzie pustym ciągiem.

Przeciążone rodzeństwo

Klasa String ma inną metodę split z następującą sygnaturą:

String[] split(String regex, int limit)
Ta metoda ma dodatkowy parametr limit: określa on, ile razy wzór regex zostanie zastosowany do oryginalnego ciągu. Zobacz poniższe wyjaśnienia:

limit > 0

Wzór jest stosowany limit-1 razy. Co więcej, długość zwracanej tablicy nie przekroczy wartości parametru limit. Ostatnim elementem tablicy będzie część ciągu występująca po ostatnim miejscu, w którym znaleziono separator. Przykład:

public class Main {
    public static void main(String[] args) {
        print("Uwielbiam Javę".split(" ", 1));
        print("Uwielbiam Javę".split(" ", 2));
        /*
         Wyjście: 
         [Uwielbiam Javę]
         [Uwielbiam, Javę]
        */
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}

limit < 0

Wyrażenie regularne separatora jest stosowane na ciągu tyle razy, ile to możliwe. Otrzymana tablica może mieć dowolną długość. Przykład:

public class Main {
    public static void main(String[] args) {
        // Zwróć uwagę na spację na końcu ciągu
        print("Uwielbiam Javę ".split(" ", -1));
        print("Uwielbiam Javę ".split(" ", -2));
        print("Uwielbiam Javę ".split(" ", -12));
        /*
         Wyjście:
        [Uwielbiam, Javę, ]
        [Uwielbiam, Javę, ]
        [Uwielbiam, Javę, ]
        
        Zwróć uwagę, że ostatnim elementem tablicy jest
        pusty ciąg. Spowodowane jest to spacją
        na końcu oryginalnego ciągu. 
        */
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}

limit = 0

Podobnie jak w przypadku, gdy limit < 0, wzór separatora stosowany jest do ciągu tyle razy, ile to możliwe. Ostateczna tablica może mieć dowolną długość. Jeśli ostatnie elementy są pustymi ciągami, zostają usunięte z ostatecznej tablicy. Przykład:

public class Main {
    public static void main(String[] args) {
        // Zwróć uwagę na spację na końcu ciągu
        print("Uwielbiam Javę ".split(" ", 0));
        print("Uwielbiam Javę ".split(" ", 0));
        print("Uwielbiam Javę ".split(" ", 0));
        /*
         Wyjście:
        [Uwielbiam, Javę]
        [Uwielbiam, Javę]
        [Uwielbiam, Javę]
        Zwróć uwagę na brak pustych ciągów na końcu tablic
        */
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}
Jeśli spojrzymy na implementację jednoparametrowej wersji metody split (Java split), to zobaczymy, że jest ona podobna do jej przeciążonego rodzeństwa, lecz z drugim argumentem ustawionym na zero:

    public String[] split(String regex) {
        return split(regex, 0);
    }

Różne przykłady

W praktyce czasami zdarza się, że mamy ciągi generowane według pewnych reguł. Taki ciąg może wejść do naszego programu z dowolnego miejsca:
  • z usługi innej firmy;
  • z żądania wysłanego do naszego serwera;
  • z pliku konfiguracyjnego;
  • i tak dalej.
W takich sytuacjach programista zazwyczaj zna „zasady gry”. Załóżmy, że programista wie, że ma do czynienia z informacjami o użytkowniku przechowywanymi według następującego wzoru:
user_id|user_login|user_email
Jako przykład weźmy kilka konkretnych wartości:
135|bender|bender@gmail.com
Załóżmy, że zadaniem programisty jest napisanie metody, która wysyła wiadomość e-mail do użytkownika. Programista ma dostęp do informacji, które są zapisane w formacie podanym powyżej. Podzadanie, które będziemy teraz dalej analizować, dotyczy sposobu odizolowania adresu e-mail użytkownika od jego pozostałych danych. Jest to jeden z przypadków, w którym metoda split może być przydatna. W końcu, jeśli spojrzymy na wzór informacji dotyczących użytkownika, zauważymy, że wyodrębnienie adresu e-mail użytkownika od reszty jest proste i polega na wywołaniu metody split w celu podzielenia ciągu znaków. Wtedy adres email będzie znajdował się w ostatnim elemencie tablicy wynikowej. Oto przykład metody, która pobiera ciąg zawierający dane użytkownika i zwraca jego adres e-mail. Dla uproszczenia, uznajmy, że ciąg danych jest zawsze w pożądanym przez nas formacie:

public class Main {
    public static void main(String[] args) {
        String userInfo = "135|bender|bender@gmail.com";
        System.out.println(getUserEmail(userInfo));
        // Dane wyjściowe: bender@gmail.com
    }

    static String getUserEmail(String userInfo) {
        String[] data = userInfo.split("\\|");
        return data[2]; // lub data[data.length - 1]
    }
}
Zwróć uwagę na separator: „\\|”. W wyrażeniach regularnych „|” jest znakiem specjalnym o specjalnym znaczeniu, więc jeśli chcemy go użyć jako zwykłego znaku (czyli tego, którego potrzebujemy w oryginalnym ciągu), to musimy uciec znak (z ang. escape a character) za pomocą dwóch ukośników wstecznych. Przeanalizuj inny przykład. Załóżmy, że mamy informacje o zamówieniu, które mają następującą strukturę:
artykul_ilosc_1,artykul_nazwa_1,artykul_cena_1;artykul_ilosc_2,artykul_nazwa_2,artykul_cena_2;...;artykul_ilosc_n,artykul_nazwa_n,artykul_cena_n
Możemy nawet przyjąć określone wartości:
1,ogórki,2,39;2,pomidory,1,89;3,bekon,4,99
Naszym zadaniem jest obliczenie całkowitego kosztu zamówienia. Tutaj będziemy musieli kilkakrotnie zastosować metodę split. Pierwszym krokiem jest podzielenie ciągu za pomocą „;” jako separatora w celu rozbicia go na jego części składowe. Wtedy każdy wynikowy podciąg będzie zawierał informacje o osobnym produkcie, które możemy później przetworzyć. Następnie, dla każdego produktu, rozdzielimy odpowiednie informacje używając symbolu przecinka „,”. Z otrzymanej tablicy ciągów weźmiemy element o określonym indeksie (ten, w którym zapisana jest cena produktu), przekonwertujemy go do postaci liczbowej i podliczymy całkowity koszt zamówienia. Napiszmy metodę, która wykona wszystkie te obliczenia:

public class Main {
    public static void main(String[] args) {
        String orderInfo = "1,ogórki,2,39;2,pomidory,1,89;3,bekon,4,99";
        System.out.println(getTotalOrderAmount(orderInfo));
        // Wyjście: 9.27
    }

    static double getTotalOrderAmount(String orderInfo) {
        double totalAmount = 0d;
        final String[] items = orderInfo.split(";");

        for (String item : items) {
            final String[] itemInfo = item.split(",");
            totalAmount += Double.parseDouble(itemInfo[2]);
        }

        return totalAmount;
    }
}
Sprawdź, czy potrafisz ustalić samodzielnie, jak działa ta metoda. Na podstawie tych przykładów możemy powiedzieć, że metoda split jest używana, gdy mamy dane sformatowane jako ciąg i musimy wyodrębnić z nich pewne bardziej szczegółowe informacje.

Podsumowanie

Przeanalizowaliśmy metodę split klasy String. Właśnie tego potrzebujesz, gdy musisz podzielić ciąg na jego części składowe za pomocą specjalnego separatora. Metoda zwraca tablicę ciągów (podciągów, które składają się na oryginalny ciąg). Akceptuje wyrażenie regularne, którego dopasowania reprezentują znak(i) separatora. Zbadaliśmy różne niuanse tej metody:
  • główny separator;
  • jego przeciążone rodzeństwo z dwoma parametrami.
Próbowaliśmy również odwzorować kilka rzeczywistych sytuacji, w których zastosowaliśmy metodę split do rozwiązania hipotetycznych, ale też całkiem realistycznych problemów.Metoda String.split() w Javie: dzielenie stringów na części - 2
Komentarze (1)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Misiu Poziom 41, Gdansk, Poland
2 kwietnia 2021
Ładne opracowanie, ale: artykul_ilosc_1 Ilość? Zadanie pokazuje kwotę za zakup po jednej sztuce produktów, więc chyba lepiej: numer, indeks. Bo jeśli zakup ma tyczyć większej niż 1 ilości danego produktu, to w kodzie powinno znaleźć się też mnożenie (dla uproszczenia z założeniem, że dostępna ilość produktów jest wystarczająca).