Centrum skryptów - Systemy operacyjne

Jak można policzyć wszystkie słowa znajdujące się w pliku tekstowym?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak można policzyć wszystkie słowa znajdujące się w pliku tekstowym?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Przeglądając witryny internetowe znalazłem skrypt, dzięki któremu można uzyskać listę wszystkich słów występujących w pliku tekstowym. To przydatne, jednak bardziej interesuje mnie jak określić, ile razy poszczególne słowa pojawiają się w tekście?

-- TZ

Cześć Skrypciarze! Odpowiedź

Cześć, TZ. Człowiek mający dużo do zrobienia powinien ustalać sobie priorytety. Począwszy od rzeczy największych, poprzez drobniejsze, ale zawsze powinien także znaleźć czas na przyjemności. Szczęściarzem jest ten, kto któremu praca sprawia tyle przyjemności, ze świata poza nią nie widzi. Tak też jest w przypadku Skrypciarza piszącego te słowa, dla którego napisanie skryptu pozwalającego policzyć słowa znajdujące się w pliku tekstowym stanowiło ogromną przyjemność. Oto on:

Const ForReading = 1



Set objDictionary = CreateObject("Scripting.Dictionary")



Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objFile = objFSO.OpenTextFile("c:\scripts\test.txt", ForReading)



strText = objFile.ReadAll

objFile.Close



strText = Replace(strText, ",", " ")

strText = Replace(strText, ".", " ")

strText = Replace(strText, "!", " ")

strText = Replace(strText, "?", " ")

strText = Replace(strText, ">", " ")

strText = Replace(strText, "<", " ")

strText = Replace(strText, "&", " ")

strText = Replace(strText, "*", " ")

strText = Replace(strText, "=", " ")

strText = Replace(strText, vbCrLf, " ")



arrWords = Split(strText, " ")



For Each strWord in arrWords

    If Len(strWord) > 0 Then

        If objDictionary.Exists(strWord) Then

            objDictionary.Item(strWord) = objDictionary.Item(strWord) + 1

        Else

            objDictionary.Add strWord, 1

        End If

        

    End If

Next



colKeys = objDictionary.Keys



For Each strKey in colKeys

    Wscript.Echo strKey & " -- " & objDictionary.Item(strKey)

Next

Piszący te słowa Skrypciarz nie napracował się zbytnio, gdyż tak naprawdę jedyne, co musiał zrobić, aby odpowiedzieć na zadane pytanie to zmodyfikować nieco skrypt już istniejący, dostępny w Centrum skryptów.

Omówmy teraz działanie skryptu. Zaczynamy od zdefiniowania stałej o nazwie ForReading i nadania jej wartości 1. Wykorzystamy tę stałą podczas otwierania pliku. Następnie tworzymy wystąpienie obiektu Scripting.Dictionary. Dlaczego? Do tego dojdziemy za moment. Na chwilę obecną zapomnijmy o obiekcie Dictionary i skoncentrujmy się na następujących wierszach kodu, za pomocą których utworzymy wystąpienie obiektu Scripting.FileSystemObject i stosując metodę OpenTextFile, otworzymy plik C:\Scripts\Test.txt:

Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objFile = objFSO.OpenTextFile("c:\scripts\test.txt", ForReading)

Po otwarciu pliku stosujemy metodę ReadAll w celu wczytania całego pliku do pamięci i zachowania go w zmiennej o nazwie strText:

strText = objFile.ReadAll

Zapisawszy zawartość pliku Test.txt w pamięci, używamy Metody Close i zamykamy plik.

Naszym następnym krokiem jest zidentyfikowanie pojedynczych słów w pliku. W zasadzie jest to bardzo proste, stosujemy metodę Split w celu utworzenia tablicy zawierającej wszystkie słowa z strText. A jak to zrobimy? Zakładając, że wszystkie słowa znajdujące się w pliku rozdzielone są za pomocą spacji, „ “, używamy tego znaku jako delimitera.

W większości wypadków działa to całkiem dobrze. Jednak istnieje pewien potencjalny problem. Przyjrzyjmy się temu próbnemu plikowi tekstowemu:

I saw the cat. The cat was black.

Ile razy w tym pliku pojawia się słowo „cat”? My zgadzamy się co do tego, że dwa. Jednakże nie zgodzi się z tym nasz skrypt. Zamiast tego, skrypt widzi dwa różne słowa, które zawierają litery c-a-t:

  • cat.
  • cat

Wiemy już w czym problem? Chodzi o kropkę występującą od razu po cat. Ponieważ nasz skrypt nie wie nic na temat zasad interpunkcji, nie ignoruje znaku kropki na końcu zdania. Znaki interpunkcyjne oraz znaki powrotu karetki mogą powodować problemy w skrypcie. Dlatego też zastosujemy serię poleceń Replace w celu odnalezienia ich i zastąpienia spacjami:

strText = Replace(strText, ",", " ")

strText = Replace(strText, ".", " ")

strText = Replace(strText, "!", " ")

strText = Replace(strText, "?", " ")

strText = Replace(strText, ">", " ")

strText = Replace(strText, "<", " ")

strText = Replace(strText, "&", " ")

strText = Replace(strText, "*", " ")

strText = Replace(strText, "=", " ")

strText = Replace(strText, vbCrLf, " ")

W wyniku tego nasz plik wygląda następująco:

I saw the cat  The cat was black

Teraz skrypt widzi, że słowo cat pojawia się w pliku dwa razy.

Uwaga. Więcej informacji znaleźć można w tej odpowiedzi Skrypciarzy.

Po oczyszczeniu naszego pliku, stosujemy funkcję Split w celu utworzenia tablicy zawierającej poszczególne słowa znajdujące się w pliku tekstowym. W przypadku naszego prostego przykładu oznacza to, że tablica arrWords będzie zawierać następujące elementy:

I 

saw 

the 

cat  

The 

cat 

was 

black

Teraz należy rozpocząć obliczanie liczby wystąpień poszczególnych słów. Do tego posłuży nam poniższy blok kodu oraz obiekt Dictionary:

For Each strWord in arrWords

    If Len(strWord) > 0 Then

        If objDictionary.Exists(strWord) Then

            objDictionary.Item(strWord) = objDictionary.Item(strWord) + 1

        Else

            objDictionary.Add strWord, 1

        End If

        

    End If

Next

A co my tutaj robimy? Dobre pytanie. Po pierwsze, uruchamiamy pętlę For Each, która przejdzie przez wszystkie elementy zawarte w tablicy, inaczej mówiąc: przez wszystkie słowa w pliku tekstowym. W przypadku każdego słowa sprawdzamy jego długość (Len) i upewniamy się, że zawiera ono więcej niż 0 znaków. (Dlaczego? Więcej informacji znaleźć można w naszej poprzedniej odpowiedzi.) Zakładając, że długość jest większa niż 0, używamy następującego wiersza kodu, aby sprawdzić, czy dane słowo naprawdę znajduje się w naszym słowniku (tzn. w obiekcie Dictionary):

If objDictionary.Exists(strWord) Then

Załóżmy, że danego słowa nie ma w słowniku. W takim wypadku, stosujemy metodę Add w celu dodania danego słowa jako nowego klucza słownika Dictionary Key. Jednocześnie nadajemy elementowi (Item) odpowiedniego słownika wartość 1:

objDictionary.Add strWord, 1

Dlaczego 1? Ponieważ jak do tej pory znaleźliśmy tylko jedno takie słowo w pliku tekstowym.

Jeżeli dane słowo juz znajduje się w słowniku, nie dodajemy go ponownie, gdyż spowodowałoby to wystąpienie błędu. Zamiast tego, zwiększamy wartość elementu (Item) o 1:

objDictionary.Item(strWord) = objDictionary.Item(strWord) + 1

Być może nie ma potrzeby o tym mówić, jednak jeżeli element miał wcześniej wartość 1, po zastosowaniu tego wiersza kodu element na wartość 2. Być może nie ma także potrzeby tłumaczenia, dlaczego zdecydowaliśmy się użyć obiektu Dictionary, a nie tablicy, a jednak: po pierwsze dlatego, że łatwiej jest zlokalizować określony klucz, a po drugie określić, czy klucz już istnieje. Więcej informacji o sposobie funkcjonowania obiektu Dictionary można znaleźć w odpowiednim artykule z serii Sesame Script (j.ang.).

Jedyne, co należy teraz zrobić, to uruchomić pętlę i powtórzyć ten proces w odniesieniu do kolejnego wyrazu znajdującego się w tablicy.

Po zakończeniu działania naszej pętli For Each, stosujemy poniższy blok kodu w celu przedstawienia wszystkich wartości kluczy (Keys) i elementów (Items) słownika Dictionary:

colKeys = objDictionary.Keys



For Each strKey in colKeys

    Wscript.Echo strKey & " -- " & objDictionary.Item(strKey)

Next

Otrzymamy raport podobny do poniższego:

I -- 1

saw -- 1

the -- 1

cat -- 2

The -- 1

was -- 1

black – 1

Jakże miło byłoby, gdyby te słowa były uporządkowane alfabetycznie. Jednak do zadanie na inny dzień.

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne