string w C# to ciąg znaków UTF-16 (wartości char). To typ referencyjny, ale w istotnych kwestiach zachowuje się jak wartość: jest niemutowalny, a == porównuje tekst, a nie tożsamość obiektu. string to słowo kluczowe C# dla typu .NET System.String; obu można używać zamiennie.
Wynik:
Porto
5
0
*****
hi
Porto has 5 letters
Stringi są niemutowalne
Żadna metoda nie zmienia stringa w miejscu. ToUpper, Replace, Trim i każda inna metoda zwracają nowy string, a oryginał zostaje nietknięty. Zapominanie o użyciu zwracanej wartości to bardzo częsty błąd przy stringach:
Wynik:
[ maya ]
[MAYA]
tea
tea and cake
Dzięki niemutowalności stringi można bezpiecznie współdzielić między wątkami i używać jako kluczy słownika. Kosztem jest to, że budowanie stringa kawałek po kawałku w pętli tworzy nowy string na każdym kroku; do tego służy StringBuilder.
Length i indeksowanie
Length to właściwość (bez nawiasów). Indeksator s[i] zwraca char na pozycji i, licząc od 0, i służy tylko do odczytu:
Wynik:
7
A
1
IndexOutOfRangeException
XB-2931
C# 8 i nowsze przyjmują też indeks liczony od końca: code[^1] to ostatni znak, to samo co code[code.Length - 1]. Żeby pobrać kilka znaków naraz, zobacz substring.
Length liczy jednostki kodowe UTF-16, a nie to, co czytelnik widzi jako znaki. Większość liter w większości języków to jedna jednostka, ale emoji i niektóre rzadkie pisma używają dwóch (para surogatów), więc "👍".Length wynosi 2.
Porównywanie stringów
== i != porównują znaki z rozróżnianiem wielkości liter. W każdym innym przypadku przekaż wartość StringComparison, która mówi, jak porównywać:
Wynik:
False
False
True
True
apple first
True
False
False
True
Którego porównania użyć:
Ordinalporównuje liczbowe kody znaków. Jest szybkie, przewidywalne i takie samo na każdej maszynie. Używaj go dla identyfikatorów, nazw plików, kluczy, wartości protokołów i wszystkiego, czego nie pokazujesz człowiekowi.OrdinalIgnoreCasedziała tak samo, ale ignoruje wielkość liter. To właściwy wybór do sprawdzeń bez rozróżniania wielkości liter, takich jak rozszerzenia plików czy nagłówki HTTP.CurrentCulture(iCurrentCultureIgnoreCase) stosuje reguły języka użytkownika, więc sortuje słowa tak, jak słownik w tym języku. Używaj go do sortowania list pokazywanych użytkownikom.InvariantCulturestosuje reguły zależne od kultury, które nie zależą od ustawień językowych użytkownika. Nadal zależy jednak od biblioteki globalizacji: współczesny .NET używa ICU, .NET Framework używa NLS z Windows, a te dwie mogą inaczej porządkować niektóre stringi.
string.Compare(a, b) i a.CompareTo(b) bez StringComparison używają bieżącej kultury, przez co ich wyniki różnią się między maszynami. Unikaj porównywania przez a.ToLower() == b.ToLower(): tworzy to dwa nowe stringi i w niektórych kulturach daje błędne odpowiedzi (klasycznym przykładem jest tureckie i z kropką i bez kropki).
Wywołanie a.Equals(b), gdy a jest null, rzuca NullReferenceException, a a == b i statyczne string.Equals(a, b) bezpiecznie obsługują null.
Znaki ucieczki
W zwykłym literale stringa ukośnik wsteczny rozpoczyna sekwencję ucieczki:
| Sekwencja | Znaczenie |
|---|---|
\n | Nowa linia (line feed) |
\r | Powrót karetki |
\t | Tabulator |
\\ | Ukośnik wsteczny |
\" | Cudzysłów |
\' | Apostrof (potrzebny tylko w literale char) |
\0 | Znak null |
\uXXXX | Znak UTF-16 według 4-cyfrowego kodu szesnastkowego, np. \u00e9 |
\U0001F44D | Znak według 8-cyfrowego kodu szesnastkowego; powyżej U+FFFF staje się dwiema wartościami char |
\xH do \xHHHH | Znak według od 1 do 4 cyfr szesnastkowych (unikaj: długość jest niejednoznaczna) |
\a, \b, \f, \v | Sygnał dźwiękowy, backspace, wysuw strony, tabulator pionowy |
\e | Znak escape, U+001B (C# 13) |
Wynik:
Name: Ana
City: Porto
She said "hi"
C:\temp\report.txt
cafe = cafe
' is a quote char
Nierozpoznana sekwencja, taka jak "\d", to błąd kompilacji (CS1009, unrecognized escape sequence), i właśnie to się dzieje, gdy ścieżkę Windows albo wyrażenie regularne zapiszesz jako zwykły string.
Stringi dosłowne i wieloliniowe
Poprzedzenie literału znakiem @ czyni go dosłownym (verbatim): ukośniki wsteczne są zwykłymi znakami, a string może zajmować kilka linii. Jedyną pozostałą sekwencją ucieczki jest "", która daje jeden cudzysłów.
Wynik:
C:\Users\ana\Documents\notes.txt
\d{3}-\d{4}
He said "ready" and left.
Rua das Flores 12
4050-262 Porto
Portugal
first line
second line
Dosłowny string wieloliniowy zawiera wszystko między cudzysłowami, łącznie z wcięciem kolejnych linii, dlatego zwykle zapisuje się je przy samym marginesie, jak powyżej. Znaki końca linii w środku są takie jak w pliku źródłowym, więc plik zapisany z końcami linii Windows daje \r\n.
C# 11 dodał surowe literały stringów (raw string literals), które rozwiązują oba problemy. Zaczynają się i kończą trzema lub więcej cudzysłowami, w ogóle nie wymagają znaków ucieczki i usuwają wcięcie równe wcięciu cudzysłowów zamykających:
// C# 11 and later
string json = """
{
"name": "Ana",
"path": "C:\temp"
}
""";
// The 4 spaces before the closing """ are removed from every line.
Jeśli sama treść zawiera """, zacznij i zakończ czterema cudzysłowami. Surowe literały łączą się też z interpolacją ($"""..."""); zobacz interpolacja stringów.
Null, pusty string i białe znaki
Zmienna typu string może mieć wartość null (brak stringa), być pusta ("", długość 0) albo zawierać same białe znaki. Dwie statyczne metody pomocnicze sprawdzają te przypadki bez ryzyka NullReferenceException:
Wynik:
null empty: True blank: True
"" empty: True blank: True
" " empty: False blank: True
"Ana" empty: False blank: False
True
Przy walidacji danych od użytkownika prawie zawsze potrzebujesz string.IsNullOrWhiteSpace. string.Empty i "" to ta sama wartość; to, którą zapiszesz, jest kwestią stylu.
Przechodzenie po znakach
String jest enumerowalny, więc foreach odwiedza każdy char. Typ char ma statyczne metody do klasyfikowania znaków:
Wynik:
letters=6 digits=4 upper=1 symbols=1
!6202tesnuS
Łączenie stringów
+ łączy stringi i działa z dowolnym typem po drugiej stronie (wywołuje ToString()). Do łączenia wielu wartości lepsza jest interpolacja albo string.Join:
Wynik:
Ana Silva, 31
Ana Silva, 31
AnaSilva
tea | coffee | juice
Total: 23
Total: 5
Dwie ostatnie linie pokazują pułapkę kolejności działań: + jest obliczany od lewej do prawej, więc gdy lewa strona jest już stringiem, każdy kolejny + oznacza konkatenację. Arytmetykę wewnątrz konkatenacji otaczaj nawiasami.
Najczęściej zadawane pytania
Jak sprawdzić długość stringa w C#?
Użyj właściwości Length: "hello".Length to 5. To właściwość, a nie metoda, więc nie ma nawiasów. Length liczy jednostki kodowe UTF-16, więc emoji lub inny znak spoza podstawowej płaszczyzny wielojęzycznej (BMP) liczy się jako 2. Wywołanie na stringu null rzuca NullReferenceException.
Jak porównywać stringi w C#?
a == b porównuje tekst i rozróżnia wielkość liter. Do porównania bez rozróżniania wielkości liter użyj string.Equals(a, b, StringComparison.OrdinalIgnoreCase). Do sortowania i ustalania kolejności służy string.Compare(a, b, StringComparison.Ordinal) albo porównanie zależne od kultury, które zwraca liczbę ujemną, zero lub liczbę dodatnią.
Jak zapisać string wieloliniowy w C#?
Poprzedź literał znakiem @, żeby był dosłowny: może zajmować kilka linii, ukośniki wsteczne są zwykłymi znakami, a cudzysłów zapisuje się jako "". W C# 11 i nowszych surowe literały stringów ograniczone przez """ też mogą zajmować kilka linii, usuwają wspólne wcięcie i w ogóle nie wymagają znaków ucieczki. Linie możesz też łączyć przez \n albo Environment.NewLine.
Czym jest string dosłowny (verbatim) w C#?
To literał stringa poprzedzony znakiem @, na przykład @"C:\Users\ana". Sekwencje ucieczki nie są przetwarzane, więc ukośnik wsteczny to po prostu ukośnik, co czyni go naturalnym wyborem dla ścieżek Windows i wyrażeń regularnych. Jedyną sekwencją ucieczki w środku jest "" dla cudzysłowu.
Jaka jest różnica między string a String w C#?
Żadna. string to słowo kluczowe C# będące aliasem typu .NET System.String, tak jak int jest aliasem System.Int32. Przyjęło się używać string w deklaracjach i string.IsNullOrEmpty(...) w wywołaniach statycznych, ale obie formy kompilują się do dokładnie tego samego.
Jakie znaki ucieczki obsługuje C#?
\n nowa linia, \r powrót karetki, \t tabulator, \\ ukośnik wsteczny, \" cudzysłów, \' apostrof, \0 znak null, \uXXXX znak UTF-16 według kodu szesnastkowego, \U0001F600 znak według 8-cyfrowego kodu (staje się parą surogatów), \a sygnał dźwiękowy, \b backspace, \f wysuw strony, \v tabulator pionowy oraz \e (C# 13) znak escape. Nieznana sekwencja, taka jak \d, to błąd kompilacji (CS1009), dlatego wyrażenia regularne zwykle zapisuje się jako stringi dosłowne.