Witam i witam ponownie. Kolejny ekscytujący wykład. W tym
wykładzie porozmawiamy więcej o łańcuchach i
funkcjach ciągów, głównie o możliwości wyszukiwania tokenizacji i analizowania łańcuchów.
Omówmy więc więcej funkcji tekstowych. Wyszukiwanie ciągu.
Wyszukiwanie ciągu.
Wszystkie te funkcje będą znajdować się w nagłówku ciągu.
Istnieje kilka funkcji wyszukiwania łańcuchów, które są szczególnie przydatne,
w których można znaleźć określony znak lub podciąg.
Nazwy tych funkcji to strchr
i strstr.
Znajdowanie pojedynczego znaku lub podciągu w ciągu.
Podamy kilka przykładów.
Istnieją również możliwości tokenizacji ciągu.
Możesz powiedzieć, co oznacza tokenizację łańcucha. Najpierw musisz zdefiniować, czym jest token.
Token to sekwencja znaków w ciągu ograniczonym ogranicznikiem.
Separator to coś, co zauważysz w ciągu
i ma specjalne znaczenie.
Tak więc token byłby, gdybyś miał pełny ciąg, to
jest Jason i byłby oddzielony spacjami.
Jeden może być tym, innym może być, innym może być Jason.
Jest to sposób na pobranie całego ciągu i rozdzielenie go
w pewnych granicach na podstawie separatora.
I chcesz się upewnić, że twój separator nie jest
czymś, co jest poprawne w rzeczywistym ciągu. Więc używasz również separatorów
podczas czytania z plików, tego samego typu koncepcji.
Gdy dzielisz zdanie na słowa, nazywa się to tokenizacją. Będziemy używać tej funkcji
o nazwie strtok.
Chciałbym również porozmawiać o kilku analizujących łańcuchach. Jest ich
mnóstwo, wiele różnych, aby sprawdzić, czy znaki
są małymi lub dużymi literami,
alfanumerycznymi lub cyframi.
Odbywa się to głównie na znakach, ale na znakach w ciągach bocznych i
można je również zastosować do całych ciągów.
Teraz wchodzimy w więcej szczegółów na temat strun.
Aby zrozumieć niektóre z tych funkcji, musimy trochę porozmawiać o wskaźnikach.
Wskaźniki to ogromna koncepcja w C.
Będziemy mieć całą sekcję poświęconą wskazówkom.
Prawdopodobnie następny lub następny.
I to dużo dyskusji. To prawdopodobnie najbardziej zagmatwany temat w tym języku.
Nie chcę teraz omawiać tego szczegółowo, ponieważ nie ma to znaczenia.
Chcę tylko go dotknąć, po prostu pokażę ci, czym jest wskaźnik, abyś mógł
zrozumieć niektóre z tych funkcji, których będziemy używać.
To jedyny cel tego. Więc jeśli nie rozumiesz w pełni wskaźników
w tym momencie po tych kilku slajdach, nie martw się.
Zatem koncepcja wskaźnika, ponownie, omówimy szczegółowo później.
Aby jednak zrozumieć niektóre z tych funkcji tekstowych, chcę rzucić okiem.
C dostarcza niezwykle użytecznego typu zmiennej, nazywanej wskaźnikiem.
Mówiłem o tym. Ma to związek z pamięcią i alokacją pamięci.
Niektóre języki, jeśli programowałeś wcześniej i
nie jesteś zupełnie nowy w programowaniu, niektóre języki automatycznie zarządzają pamięcią.
Przydzielą ci pamięć i usuwają ją, język taki jak java to robi.
Nazywa się zbieraczem śmieci. Język taki jak c tego nie robi.
Więc za każdym razem, gdy tworzysz pamięć do
używania wskaźników, musisz ją usunąć.
Ale czym jest wskaźnik, jest bardzo
przydatny, a czym jest zmienna, która przechowuje adres.
Pamiętaj, adres jest czymś w pamięci.
Zwykle jest szesnastkowy.
Wartość adresu znajduje się w innej lokalizacji w pamięci.
Wskaźnik wskazuje tylko na adres, którego adres zawiera wartość.
W przeszłości używaliśmy adresów z funkcją scanf.
Pamiętaj, że ten symbol ampersand, którego użyliśmy, to adres operatora.
Funkcja Scanf jako drugi parametr
musiałaby przyjąć zmienną, którą chciałeś przechowywać
dane, ta zmienna musi być wskaźnikiem.
I tak funkcja scanf oczekiwała wskaźnika.
Aby utworzyć samą liczbę całkowitą, nie jest to wskaźnik,
ale jeśli uzyskasz jej adres, staje się teraz wskaźnikiem.
Więc używamy znaku ampersand, aby uzyskać adres pierwotnego typu danych.
Więc trochę znasz pojęcie adresu.
Pamiętaj, że od teraz za pomocą wskaźników
tworzysz liczbę int, która nie jest
wskaźnikiem i jest równa 25.
Ale jeśli otrzymasz znak ampersand, który jest jego adresem, możesz przypisać go do wskaźnika.
Wskaźnik ma specjalną składnię w c, gwiazdka reprezentuje wskaźnik.
Więc zadeklarowaliśmy numer zmiennej o wartości 25, a następnie
zadeklarowaliśmy wskaźnik za pomocą gwiazdki o nazwie pNumber,
która zawiera adres liczby.
I znowu gwiazdka jest używana do zadeklarowania wskaźnika, dzięki czemu wiesz,
że jest to typ danych wskaźnika.
Aby uzyskać wartość zmiennej p, ponieważ liczba
p jest czym? To wskaźnik, który wskazuje adres w pamięci.
Jeśli tylko spróbujesz spojrzeć na wartość liczby p, poda ci ona adres.
Jeśli chcesz uzyskać wartość tego, na co wskazuje adres, musisz go usunąć.
Istnieje więc specjalna
składnia, w której c używa go jako gwiazdki i nazwy zmiennej, w ten
sposób można faktycznie uzyskać dostęp do lokalizacji pamięci, która zawiera wartość.
Więc jeśli chcesz przypisać dane do tej lokalizacji pamięci, musisz powiedzieć gwiazdkę p numer.
Ponownie efekt jest taki, że uzyskuje dostęp do danych przechowywanych pod adresem określonym przez wskaźnik.
Tak więc, gdy mówimy o wskazówkach, staje się to bardzo zagmatwane, ponieważ nie jesteś przyzwyczajony do tej koncepcji.
Myślisz, że zmienna ma wartość, to wszystko. Ale zmienna może mieć adres, a
adres może mieć wtedy wartość.
Ten slajd jest próbą zilustrowania tego, o czym właśnie wspomniałem.
Znalazłem to w książce, którą przeczytałem.
To slajd, który pokazuje koncepcję wskaźnika w pamięci i
sposób działania elementów z adresami.
Więc w pewnym sensie powtarzam to, o czym właśnie wspomniałem.
Ale wartością ampersand liczba jest adres, pod którym znajduje się liczba.
Więc jeśli masz dwie zmienne, liczbę i
liczbę p, liczba p jest wskaźnikiem, liczba to
int, przy okazji musisz również określić typ wskaźnika.
Mimo że wskaźnik jest
adresem, nadal określasz typ lub miejsce, na które wskazuje adres.
Więc int star liczba p będzie równa adresowi liczby.
Liczba jest w pamięci, wskazuje
na przykład adres tysiąca i ma wartość 25.
Numer P ma adres 105 dla
tego rzeczywistego numeru p, ale
wartość tego adresu to adres 1000.
Aby uzyskać wartość liczby p, musiałbyś wyłuskać 1000, co da
ci 25.
Powód, dla którego wspominam o tym wszystkim
o wskaźnikach, ponieważ wiele funkcji łańcuchowych zwraca wskaźniki.
To naprawdę nie będzie miało aż tak wielkiego znaczenia.
Jest to ważne tylko wtedy, gdy chcesz zrozumieć, w jaki sposób otrzymujesz określony znak w tablicy.
Ale chciałem o nich krótko wspomnieć.
W porządku, jeśli koncepcja nie dociera teraz, ponieważ omówimy ją
szczegółowo w późniejszej sekcji.
Ale zrozum, że funkcje łańcuchowe, których teraz będziemy używać, będą zwracać wskaźniki, a
wtedy być może użyjesz tego powrotu, aby zrobić coś pożytecznego.
W przeszłości, kiedy używaliśmy kopii str i porównań str, przekazywaliśmy
wskaźniki, ale nigdy nie zwracało to wskaźników, nigdy nie musieliśmy używać tego wskaźnika.
Teraz, gdy musimy użyć wskaźnika, chcę tylko krótko opisać, co to oznacza.
Wskaźnik będzie po prostu wskazywał adres.
A potem możesz użyć tego adresu do parsowania lub cokolwiek innego, co musisz zrobić.
Miejmy nadzieję, że to cię nie przytłoczyło. Ponownie, nie martw się, jeśli nie w pełni go rozumiesz.
Przejdziemy teraz przez
kilka przykładów analizy, tokenizacji i wyszukiwania ciągów.
Aby wyszukać ciąg, o którym wspomnieliśmy, użyjesz strchr lub strstr.
Strchr przeszukuje dany ciąg dla pojedynczego znaku.
Pierwszym argumentem funkcji jest szukany ciąg znaków,
który będzie adresem tablicy znaków.
Drugi argument to postać, której szukasz.
Za chwilę podamy przykład. Tak więc funkcja przeszuka
ciąg zaczynający się od początku i
zwróci wskaźnik do pierwszej pozycji w ciągu, w którym znak został znaleziony.
Właśnie dlatego wskaźnik jest teraz ważny,
ponieważ nie zwracamy całej wartości, zwracamy wskaźnik
do znaku wewnątrz
ciągu, a ten adres zasadniczo reprezentuje indeks tablicy.
A więc adres tej pozycji w pamięci, jest to gwiazda typu znakowego i
jest opisana jako wskaźnik do
znaku, który w rzeczywistości jest tylko pojedynczym znakiem w pamięci.
Aby przechowywać zwracaną wartość, musisz utworzyć zmienną, która może przechowywać adres znaku,
więc musisz utworzyć wskaźnik.
Jeśli znak zostanie teraz znaleziony, funkcja zwraca specjalną wartość, która jest równa null.
Null oznacza, że wskaźnik niczego nie wskazuje.
Używamy wartości null, gdy mówimy o wskaźnikach, a null oznacza
po prostu, że nic nie znalazło. Więc to na nic nie wskazuje.
Kiedy wskazuje na coś, wskazuje na adres, pod którym znalazłeś ten znak, a
następnie możesz rozpocząć analizowanie od tego miejsca.
Pamiętaj, że z poprzednich
wykładów, kiedy tworzysz tablicę znaków w
pamięci, każdy znak jest reprezentowany jako bajt.
A jeśli analizujesz ciąg
i chcesz zobaczyć, gdzie zaczyna się określony znak w tym ciągu, zwracasz
ten bajt, a następnie możesz zacząć szukać od tego miejsca.
Więc str char, jak tego używasz, jest to.
Mówisz, że tworzysz ciąg znaków i inicjalizujemy
go tutaj szybkim brązowym lisem.
Następnie tworzymy pojedynczy znak i inicjalizujemy go za pomocą q.
Następnie tworzymy wskaźnik, ponieważ musimy utworzyć wskaźnik, ponieważ to jest to, co jest zwracane z ciągu znaków,
to pozwala nam zobaczyć, gdzie w tym ciągu znaleźliśmy znak.
Zamierzamy zainicjować nasz wskaźnik na null. Ponieważ w tej chwili to na nic nie wskazuje.
Następnie wywołamy str char, przekażemy nasz ciąg, który jest szybkim brązowym lisem, i przekażemy
nasz pojedynczy znak, którym jest q.
To, co się wydarzy, zajrzy do wnętrza szybkiego brązowego lisa.
Za pierwszym razem, gdy znajdzie q, zwróci adres tego q.
Więc p got
char naprawdę będzie wskazywać na czwarty indeks str.
Ponieważ t jest mniejsze od zera, h jest mniejsze niż jeden, e jest mniejsze niż dwa,
przestrzeń jest mniejsze niż trzy, q jest mniejsze niż cztery.
Więc p got char będzie wskazywać na q w szybkim brązowym lisie.
Dzięki temu możesz dokładnie zobaczyć, gdzie ten znak zaczyna się w tym ciągu.
Zatem pierwszym argumentem do str char jest adres pierwszej przeszukiwanej lokalizacji, to
jest szukany ciąg.
Drugi argument to poszukiwany znak, znak, którego chcesz szukać,
pojedynczy znak.
Oczekuje, że drugi argument będzie typu int.
Więc technicznie str char, drugi argument przyjmuje.
Ale kompilator c automatycznie przekonwertuje wykres na int.
Zasadniczo otrzyma wartość ASCII.
Tak więc możesz w rzeczywistości zdefiniować pojedynczy
znak q zamiast pojedynczego znaku, możesz zdefiniować go jako int.
To tylko bardziej techniczny aspekt, o którym chciałem, żebyś wiedział.
Ale p got char będzie wskazywać na wartość quick brown
fox, ponieważ zacznie się od q, a następnie przejdzie do terminatora zerowego, jeśli spróbujesz go wydrukować.
Więc tak naprawdę będzie to szybki brązowy lis, kiedy uruchomisz ten przykład.
W ten sposób możesz wyszukać pojedynczy znak w całym ciągu.
Użyj str char, a następnie użyj wskaźnika, a następnie wyświetl wskaźnik.
Jak wyświetlić ten wskaźnik? W ten sam sposób, w jaki wyświetlasz inne znaki, użyj printf, percent s.
Jest to więc fajny mechanizm wyszukiwania znaków w całym łańcuchu.
Jeśli chcesz wyszukać ciąg wewnątrz łańcucha, który byłby podłańcuchem,
użyj strstr.
Jest to prawdopodobnie najbardziej przydatna ze wszystkich funkcji wyszukiwania.
Przeszukuje jeden ciąg pod kątem wystąpienia podciągu.
I zwraca wskaźnik do pozycji w pierwszym ciągu, w której znajduje się podłańcuch,
bardzo podobna do ciągu znaków, ale przeszukuje cały ciąg. Jeśli nie znalazł żadnego dopasowania, zwraca wartość null.
Pierwszym argumentem jest łańcuch, który ma być przeszukiwany, tak jak str char.
Drugi to podciąg, którego szukasz, kolejny ciąg. Oto przykład.
Wygląda bardzo podobnie do poprzedniego, z wyjątkiem tego, że
zamiast szukać pojedynczego znaku, szukamy słowa, ciągu.
Mamy więc słowo, które jest równe pies.
I mamy tekst, który mówi, że każdy pies ma swój dzień.
Tworzymy nasz wskaźnik ponownie, ponieważ musi być - tak zwraca funkcja.
Kiedy wywołujemy strstr, przekazujemy w tekście ciąg, na który chcemy spojrzeć.
A następnie drugim argumentem jest słowo, które chcemy znaleźć w tym ciągu.
Więc wyszuka tekst, który jest pierwszym wystąpieniem ciągu zapisanego w słowie.
Pies strunowy pojawia się na siódmym znaku w tekście.
Jeśli spojrzysz na tekst.
Tekst sub 6 będzie równy dog, od tego się zaczyna.
Tak więc wskaźnik będzie wskazywał na adres tekstu plus 6 psów
i zacznie tam, a następnie przejdzie do terminatora zerowego.
Więc p znaleziony będzie pies ma swój dzień.
Należy też zachować ostrożność, ponieważ w wyszukiwaniu rozróżniana jest wielkość liter.
Jeśli faktycznie podałeś duże D-O-G, niczego nie znajdziesz,
a jedynie poszukasz właściwego przypadku.
Ale jest to używane do znajdowania podciągów i łańcuchów, bardzo przydatne,
ponieważ wiele razy w programie, o którym zamierzasz powiedzieć, robi ten ciąg
wewnątrz tego ciągu, ponieważ jest prawie podobny do grepa, jeśli kiedykolwiek używałeś grep w Linuksie.
Mam nadzieję, że to ma sens. Tokenizacja ciągu.
Token to sekwencja znaków, z których jeden jest ciągiem ograniczonym przez separator, wiemy o tym.
Separatorem może być wszystko, ale powinno to być coś unikalnego dla tego ciągu.
Nie używaj separatora jako „A”, ponieważ teraz znajdzie w tym
ciągu coś poprawnego w słowie.
Nadaj mu wyjątkowy charakter, np. Spację lub przecinek. To znowu jest używane jako granica dla
zwykle słów w jednym ciągu.
Więc dzieli zdanie na słowa, nazywa się to tokenizacją.
Ta funkcja strtok służy do tokenizacji ciągu.
Wymaga dwóch argumentów.
Ciąg do tokenizacji, czyli cały ciąg zawierający spacje i ograniczniki.
A następnie ciąg zawierający wszystkie dodatnie ograniczone znaki.
Możesz określić, co chcesz ustawić jako granicę.
Oto przykład.
Tworzymy tablicę znaków 80.
Mówi cześć, jak się masz, jesteś dash, nazywam się dash Jason.
Następnie tworzymy ciąg stały, który reprezentuje ogranicznik, którym
jest minus, myślnik. Wygląda trochę inaczej, ale to wciąż minus, kreska,
obie są kreskami.
Następnie tworzymy nasz wskaźnik, który jest tokenem.
Ponieważ strtok zwróci każdy
nasz token.
Więc jeśli wywołasz nasz strtok i przekażemy
ciąg i przekażemy nasze
ograniczniki s, token będzie równy pierwszej znalezionej rzeczy.
Więc gdy po raz pierwszy wywołasz strtok, będzie to równe cześć,
jak się masz spacja, a następnie znajdzie dopasowanie z myślnikiem.
A jeśli zadzwonisz po
raz drugi, to wydrukuje moje imię.
Jeśli zadzwonisz po raz
trzeci, wydrukuje Jason, ponieważ przechodzi przez myślniki.
Dlatego mamy tutaj pętlę while. Mówimy, że gdy token nie jest równy
null, wydrukuj token.
Następnie otrzymujemy następny token, wywołując strtok.
I mówimy null jako nasz pierwszy parametr, a
s jest drugim parametrem, a
następnie wyświetlamy my. Spójrzmy więc na
to w blokach kodu, ponieważ uczyni to bardziej zrozumiałym.
Zbudujmy to. Właśnie przejrzeliśmy ten przykład.
Chcę wam pokazać, jaki jest wynik, więc jasne jest, co się tutaj dzieje.
Więc tutaj zobaczysz, że mówi, że wypisuje
pierwszy token, czyli cześć, jak się masz.
Cóż, pierwszą rzeczą, jaką robi, jest
znalezienie pierwszego tokena, wydrukowanie go, cześć, jak się masz, mam na imię, a potem Jason.
Więc teraz witamy, jak się masz,
znajduje pierwszy myślnik, drukuje go. Moje imię to znajduje następny token,
a trzeci to Jason. Ale musisz wywołać token
trzy razy, aby otrzymać każdy token.
Pierwsza z nich będzie tokenizować na str.
Zobacz następny, który możesz przekazać jako null, ponieważ nie chcesz ponownie patrzeć, po prostu chcesz zdobyć następny token.
I tak mijasz null w drugim i po prostu mijasz s.
To da ci następny żeton str. Już żeton.
W ten sposób możesz użyć strtok. Bardzo pomaga przy parsowaniu.
Możesz coś przeanalizować i wyjść poza pewne granice.
Ostatnie funkcje, o których chcę porozmawiać, to te analizujące funkcje łańcuchowe.
Jest ich mnóstwo, więc podałem tutaj mały stolik.
Jest niższy, jest wyższy. Robi dokładnie to, co myślisz, że zrobiłby.
Sprawdza, czy znak jest pisany małymi czy dużymi literami.
Testujemy określone znaki, ale są one używane w łańcuchach.
A zatem argumentem każdej z tych funkcji jest znak, którego chcesz szukać.
A następnie wszystkie te funkcje zwracają niezerową wartość
typu int, jeśli znak znajduje się w testowanym zestawie.
Więc zamierzamy przekazać int znaki wewnątrz szukając wewnętrznych słów.
Jeśli w słowie znajduje się duża litera, powie nam to i możemy
jej użyć również do parsowania poszczególnych elementów w sposób znakowy.
Dlatego wartości zwracane zostaną przekonwertowane na prawdę lub fałsz, aby można
było ich używać również jako wartości logicznych, co jest miłe.
Więc is lower zwróci prawdę,
jeśli słowo lub znak ma małą literę.
Cóż, oto ładny przykład, który
chciałem przejrzeć, który policzy liczbę cyfr liter w całym ciągu.
Więc uruchommy to, ponieważ będzie to
jasne, ale powinieneś zauważyć, że tworzymy bufor, nasz
bufor wejściowy, a następnie tworzymy trzy liczby całkowite do zliczenia.
Mówimy użytkownikowi, aby wprowadził ciąg mniejszy
niż tak wiele znaków, a następnie go wczytujemy.
Następnie przyjrzymy się temu ciągowi, aby sprawdzić,
czy zawiera określone znaki.
I tak będziemy iterować przez ten ciąg,
patrząc na każdy indeks w tablicy.
Oto nasz przykład.
Ponownie, bufor to nasza tablica znaków, która
będzie przechowywać dane wejściowe. Zamierzamy użyć scanf, aby to wypełnić.
Musimy wpisać nasz ciąg bez spacji, jest to pojedynczy ciąg.
Przejdziemy przez to, przejdziemy przez każdy element w buforze, a następnie wywołamy
funkcje is alpha, is digit lub is punct, aby zobaczyć, czy
te znaki tam są, a następnie
zwiększy się na podstawie tego, czy to, czy nie zwraca prawdę lub fałsz, a
następnie wyświetli, ile liter, cyfr i znaków interpunkcyjnych znajduje się w tym ciągu.
Uruchommy to.
Zamierzam wpisać coś z kilkoma dużymi literami,
może kilkoma cyframi.
Potem, kiedy wrócę do powrotu, policzy wszystko. Więc mówi,
że mój układ kierowniczy zawierał 24 litery, 4 cyfry
i 1 znak interpunkcyjny, dwukropek.
Ładny, zgrabny, mały program, który wykorzystuje te funkcje
znakowe, ale jest przydatny przy analizowaniu ciągu znaków, ponieważ
to właśnie robisz, analizujesz ciąg, ale przechodzisz po
prostu znak po znaku. Dziękuję Ci.