Menu

Stringi w Golang: Split, Join, Contains, Replace i więcej

Praca ze stringami w Go: pakiet strings (Split, Join, Contains, Replace, Fields, TrimSpace, ToUpper), wydajne budowanie stringów przez strings.Builder, wieloliniowe surowe stringi, niezmienność i dlaczego len liczy bajty.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

String w Go to niezmienny ciąg bajtów, zwykle tekst w UTF-8. Operatory działają na samym stringu (+, ==, <, indeksowanie, wycinanie), a cała reszta znajduje się w standardowym pakiecie strings.

Dzielenie stringów

FunkcjaDzieli w miejscuUwagi
Split(s, sep)każdego sepzachowuje puste części; Split("", ",") zwraca [""], jeden pusty string
SplitN(s, sep, n)co najwyżej na n częściostatnia część zawiera resztę
SplitAfter(s, sep)każdego sepzostawia separator przy każdej części
Fields(s)ciągów białych znakównigdy nie zwraca pustych części
FieldsFunc(s, f)znaków, dla których f zwraca truewłasne separatory
Cut(s, sep)tylko pierwszego sepzwraca część przed, po i czy znaleziono (Go 1.18)

Przypadek Split("", ",") łapie wiele osób: puste wejście daje slice o długości 1, a nie 0. Przy dzieleniu danych od użytkownika Fields albo wcześniejsze sprawdzenie s == "" pozwala uniknąć fantomowego pustego elementu.

strings.Cut to najczystszy sposób na podzielenie key=value, user@host i podobnych par. Go 1.24 dodało też wersje z iteratorami, strings.SplitSeq i strings.FieldsSeq, które zwracają części po jednej, bez budowania slice'a.

Wyszukiwanie

FunkcjaZwraca
Contains(s, sub)true, jeśli sub występuje w s
ContainsAny(s, chars)true, jeśli występuje dowolny znak z chars
HasPrefix(s, p) / HasSuffix(s, p)true, jeśli s zaczyna się lub kończy na p
Index(s, sub)pozycję w bajtach pierwszego dopasowania albo -1
LastIndex(s, sub)pozycję w bajtach ostatniego dopasowania albo -1
Count(s, sub)liczbę nienakładających się dopasowań
EqualFold(a, b)równość bez rozróżniania wielkości liter

Każde wyszukiwanie rozróżnia wielkość liter, z wyjątkiem EqualFold. Aby szukać bez rozróżniania wielkości liter, zamień obie strony na małe litery albo użyj EqualFold do porównania całych stringów.

Przekształcanie

Jedna pułapka: Trim, TrimLeft i TrimRight przyjmują zestaw znaków, a nie prefiks. strings.TrimLeft("abcab", "ab") usuwa każde początkowe a i b i zwraca "cab". Aby usunąć dokładny prefiks lub sufiks, użyj TrimPrefix i TrimSuffix.

Łączenie i strings.Builder

+ łączy stringi, a fmt.Sprintf formatuje wartości w jeden string. Oba za każdym razem alokują nowy string, bo stringi są niezmienne. Przy kilku operacjach to nie problem, ale w pętli jest wolne, bo każde += kopiuje wszystko, co zbudowano do tej pory. Użyj zamiast tego strings.Builder:

Zerowy strings.Builder jest gotowy do użycia. Implementuje io.Writer, więc fmt.Fprintf zapisuje do niego bezpośrednio. Najpierw wywołaj b.Grow(n), jeśli z grubsza wiesz, jak duży będzie wynik. Nie kopiuj Builder po zapisaniu do niego danych; przekazuj wskaźnik.

Wieloliniowe i surowe stringi

Go ma dwa rodzaje literałów stringów:

Stringi w podwójnych cudzysłowach przetwarzają sekwencje ucieczki (\n, \t, \", \\, \u00e9) i muszą mieścić się w jednej linii. Surowe stringi w backtickach biorą wszystko dosłownie, łącznie ze znakami nowej linii, więc tak zapisuje się wieloliniowe stringi, wyrażenia regularne, JSON i ścieżki Windows. Surowy string nie może zawierać backticka, a znaki powrotu karetki są z niego usuwane. Zauważ, że powyższe zapytanie zaczyna się od znaku nowej linii, bo literał zaczyna się zaraz po otwierającym backticku.

Długość, indeksowanie i podciągi

len(s) to liczba bajtów. s[i] to bajt, a s[i:j] to podciąg według pozycji w bajtach:

ï i é zajmują po dwa bajty, więc string ma 12 bajtów i 10 znaków. Wycinanie po bajtach jest bezpieczne, o ile pozycje pochodzą z strings.Index lub podobnych funkcji, które zwracają przesunięcia w bajtach na granicach znaków. Aby wziąć „pierwsze n znaków”, najpierw zamień string na []rune. Strona o runach i bajtach szczegółowo wyjaśnia UTF-8.

Stringi są niezmienne

Nie możesz zmienić bajtu w miejscu: s[0] = 'H' to błąd kompilacji (cannot assign to s[0] (neither addressable nor a map index expression)). Każda funkcja z strings zwraca nowy string. Aby edytować, zamień na []byte lub []rune, zmień slice i zamień z powrotem:

b := []byte("hello")
b[0] = 'H'
s := string(b) // "Hello"

Niezmienność sprawia też, że podciągi są tanie: s[2:5] współdzieli pamięć z s zamiast ją kopiować. Druga strona medalu: mały podciąg ogromnego stringa utrzymuje przy życiu cały ogromny string. Użyj strings.Clone (Go 1.20), gdy zachowujesz krótki fragment dużego wejścia.

Porównywanie stringów

== i != porównują zawartość, a <, > porównują bajt po bajcie, co dla ASCII oznacza kolejność alfabetyczną. strings.Compare istnieje, ale rzadko jest potrzebne; slices.Sort na []string używa <. Do sortowania tekstu w innych językach z uwzględnieniem reguł lokalnych użyj golang.org/x/text/collate.

Konwersja innych typów

Liczby zamieniasz na stringi przez strconv.Itoa, strconv.FormatFloat lub fmt.Sprintf, a stringi na liczby przez strconv.Atoi i strconv.ParseFloat. Nie pisz string(42): daje to znak o punkcie kodowym 42, czyli "*". Pełną tabelę znajdziesz na stronie o konwersji typów.

Najczęściej zadawane pytania

Jak podzielić string w Go?

Użyj strings.Split(s, sep): strings.Split("a,b,c", ",") zwraca ["a" "b" "c"]. Aby dzielić po dowolnym ciągu białych znaków i pomijać puste części, użyj strings.Fields(s). strings.SplitN ogranicza liczbę części, a strings.Cut dzieli raz, wokół pierwszego separatora.

Jak zapisać wieloliniowy string w Go?

Użyj surowego literału stringa w backtickach:

query := `SELECT id, name
FROM users
WHERE active = true`

Wszystko między backtickami jest brane dosłownie, łącznie ze znakami nowej linii i ukośnikami wstecznymi. Surowy string nie może zawierać backticka.

Jak sprawdzić, czy string zawiera podciąg w Go?

strings.Contains(s, substr) zwraca bool. Powiązane funkcje: strings.HasPrefix, strings.HasSuffix, strings.Index (pozycja albo -1), strings.ContainsAny (dowolny znak z zestawu) oraz strings.EqualFold do porównania bez rozróżniania wielkości liter.

Jaki jest najszybszy sposób łączenia stringów w Go?

Dla kilku stringów wystarczy +. Gdy budujesz string w pętli, użyj strings.Builder: wywołuj wielokrotnie WriteString, a na końcu raz String(). Powtarzane += w pętli za każdym razem kopiuje cały string, więc spowalnia w miarę jego wzrostu. Aby połączyć slice separatorem, użyj strings.Join.

Dlaczego len zwraca złą długość mojego stringa?

len(s) zwraca liczbę bajtów, a nie znaków. Stringi w Go są w UTF-8, gdzie znaki spoza ASCII zajmują od 2 do 4 bajtów, więc len("héllo") to 6. Użyj utf8.RuneCountInString(s), aby poznać liczbę punktów kodowych Unicode.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ