Tworzenie napisów w R
Napis w R to tekst w cudzysłowie. Działają zarówno cudzysłowy podwójne, jak i pojedyncze, i znaczą dokładnie to samo. Konwencja to cudzysłowy podwójne, a pojedyncze stosuje się wtedy, gdy sam tekst zawiera cudzysłów podwójny:
Sekwencje z ukośnikiem odwrotnym działają jak w większości języków: \" dla dosłownego cudzysłowu, \n dla nowej linii, \t dla tabulatora, \\ dla samego ukośnika odwrotnego.
A teraz błąd, który każdy początkujący w R popełnia dokładnie raz: pytanie napisu o długość przez length().
nchar() liczy znaki, czyli 5. length() liczy elementy wektora, a pojedynczy napis to wektor z jednym elementem, więc wynik to 1. W R wszystko jest wektorem, także tekst, a wszystkie funkcje z tej strony po cichu działają element po elemencie na całych wektorach tekstowych. To zaleta, gdy już przestanie cię zaskakiwać.
Łączenie napisów: paste() i paste0()
R nie ma + dla napisów. Do łączenia służy paste(), która domyślnie łączy argumenty spacją, i paste0(), która łączy je bez niczego:
Ponieważ paste jest wektorowa, przekazanie jej wektora buduje wiele napisów naraz. Tak w jednej linii generuje się nazwy plików, etykiety i identyfikatory:
A argument collapse robi coś odwrotnego: skleja cały wektor w jeden napis z wybranym separatorem:
Zapamiętaj podział: sep określa klej między argumentami, a collapse klej między elementami jednego wektora. Możesz użyć obu w jednym wywołaniu.
Formatowanie przez sprintf()
Gdy potrzebujesz liczb sformatowanych w tekście (stała liczba miejsc po przecinku, wyrównana szerokość), paste() przestaje wystarczać i do akcji wchodzi sprintf(). Używa kodów formatu w stylu C: %s dla napisów, %d dla liczb całkowitych, %f dla liczb dziesiętnych:
%.1f oznacza „jedno miejsce po przecinku”, %.3f trzy, a %05d dopełnia zerami do pięciu cyfr. Podwójne %% daje dosłowny znak procentu. sprintf() też jest wektorowa, więc potrafi sformatować całą kolumnę wartości jednym wywołaniem. Wzorzec raportowania sprintf() + cat() opisuje artykuł o wejściu i wyjściu.
Zmiana wielkości liter i wycinanie: toupper(), tolower(), substr()
Zmiana wielkości liter robi dokładnie to, co mówi nazwa:
tolower() najbardziej przydaje się przy normalizowaniu chaotycznych danych przed porównaniem: "Yes", "YES" i "yes" stają się tą samą wartością.
substr(x, start, stop) wycina fragment według pozycji znaków, licząc od 1 (R wszędzie indeksuje od 1):
Oba końce są włączone: pozycje od 1 do 11 dają "Programming".
Wyszukiwanie i zamiana: sub(), gsub() i grepl()
sub() zamienia pierwsze wystąpienie wzorca; gsub() („global substitute”) zamienia wszystkie:
Jeden kluczowy szczegół: wzorzec jest domyślnie wyrażeniem regularnym, a nie dosłownym tekstem. Znaki regex, takie jak ., *, ( i ?, mają specjalne znaczenie: goła . pasuje do dowolnego znaku. Gdy chodzi ci o dosłowny tekst, przekaż fixed = TRUE:
Pierwsza linia daje a-b-c; druga daje -----, bo jako regex . dopasowała każdy pojedynczy znak. Dopóki nie poznasz wyrażeń regularnych, niech fixed = TRUE będzie twoim domyślnym wyborem, a nic cię nie ugryzie.
grepl() niczego nie zamienia: sprawdza, czy każdy element pasuje, i zwraca wektor logiczny. Dzięki temu to standardowe narzędzie do filtrowania tekstu:
Pierwszy wynik oznacza, które nazwy plików zawierają .csv; drugi używa tego wektora logicznego, żeby zostawić tylko dopasowania.
Dzielenie i przycinanie: strsplit() i trimws()
strsplit() tnie napis według separatora. Ma jedną osobliwość: zwraca listę, bo potrafi podzielić wiele napisów naraz. Przy pojedynczym napisie weź pierwszy element przez [[1]]:
A trimws() usuwa białe znaki, w które prawdziwe dane zawsze są owinięte:
Domyślnie przycina oba końce; which = "left" albo "right" przycina tylko jedną stronę (nazwy odnoszą się do początku i końca napisu).
Alternatywa: stringr
Wszystko powyżej to bazowy R: zawsze dostępny, bez instalacji. Pakiet stringr z tidyverse opakowuje te same operacje w spójny schemat nazw str_*, w którym napis jest zawsze pierwszym argumentem, co wielu osobom łatwiej zapamiętać (instalację opisuje artykuł o pakietach):
library(stringr)
str_detect(files, "csv") # like grepl(), data first
str_replace_all(s, "good", "great") # like gsub(), arguments reordered
str_length("hello") # like nchar()
Funkcje tekstowe bazowego R i tak warto znać: spotkasz je w każdym skrypcie, każdej odpowiedzi na Stack Overflow i każdym komunikacie o błędzie. Najpierw naucz się nazw z bazowego R; po stringr sięgnij, gdy niespójna kolejność argumentów zacznie cię irytować.
Najważniejsze informacje
- Napisy zapisuje się zwyczajowo w cudzysłowach podwójnych;
nchar()liczy znaki,length()liczy elementy wektora. - Łącz przez
paste()/paste0();sepskleja argumenty,collapseskleja wektor w jeden napis. sprintf()obsługuje sformatowany wynik:%s,%d,%.2f.sub()zamienia pierwsze dopasowanie,gsub()wszystkie,grepl()sprawdza dopasowania. Wszystkie domyślnie używają regex, więc przekażfixed = TRUEdla dosłownego tekstu.strsplit()zwraca listę (weź[[1]]);trimws()czyści wejście z nadmiarowymi spacjami.
Dalej: wprowadzanie tekstu do programów i wyprowadzanie go z nich, czyli wypisywanie przez print() i cat() oraz wczytywanie danych od użytkownika.
Najczęściej zadawane pytania
Jak łączyć napisy w R?
Przez paste() albo paste0(): R nie ma + dla napisów. paste("data", "science") daje "data science" (domyślnie ze spacją), a paste0("data", "science") łączy bez niczego. Użyj sep =, żeby zmienić separator, i collapse =, żeby złączyć cały wektor w jeden napis.
Jak sprawdzić długość napisu w R?
nchar("hello") zwraca 5, czyli liczbę znaków. length("hello") zwraca 1: w R length() liczy elementy wektora, a pojedynczy napis to wektor z jednym elementem. Mylenie length() z nchar() to klasyczny błąd początkujących.
Czym różni się sub() od gsub() w R?
Obie wyszukują i zamieniają, ale sub() zamienia tylko pierwsze dopasowanie, a gsub() ("global sub") zamienia wszystkie. Obie domyślnie traktują wzorzec jako wyrażenie regularne. Przekaż fixed = TRUE, żeby dopasować dosłowny tekst.
Jak podzielić napis w R?
strsplit(x, split) dzieli według wzorca, ale zwraca listę (bo potrafi podzielić wiele napisów naraz). Przy pojedynczym napisie weź pierwszy element: strsplit("a,b,c", ",")[[1]] daje wektor tekstowy "a" "b" "c".