Centrum skryptów - Systemy operacyjne

Jak wybrać i zapisać określone wiersze z tekstu? 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 wybrać i zapisać określone wiersze z tekstu?

Cześć Skrypciarze! Chciałbym mieć możliwość czytania pliku tekstowego, wybierania wierszy zaczynających się określonym słowem (na przykład Failure – niepowodzenie), a następnie zapisywania z powrotem do tego samego pliku tylko tych wierszy. Czy istnieje taka możliwość?

-- AC

Cześć AC! Dla uproszczenia zakładamy, że Twój plik tekstowy wygląda podobnie do tego:

 

Success – Operation succeeded 10/1/2004.

Success – Operation succeeded 10/2/2004.

Failure – Operation failed 10/3/2004.

Success – Operation succeeded 10/4/2004.

Failure – Operation failed 10/5/2004.

Success – Operation succeeded 10/6/2004.

Failure – Operation failed 10/7/2004.

Failure – Operation failed 10/8/2004.

Chciałbyś, żeby skrypt odczytał tekst, usunął wszystkie wiersze zaczynające się od Success (powodzenie), a następnie zapisał plik w takiej postaci, by zawierał on wyłącznie informacje o operacjach zakończonych niepowodzeniem. Innymi słowy, chcesz by poprawiony plik wyglądał tak:

Failure – Operation failed 10/3/2004.

Failure – Operation failed 10/5/2004.

Failure – Operation failed 10/7/2004.

Failure – Operation failed 10/8/2004.

Czy można to zrobić przy pomocy skryptu? Oczywiście:

Const ForReading = 1

Const ForWriting = 2



Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objTextFile = objFSO.OpenTextFile _

    ("test.log", ForReading)



Do Until objTextFile.AtEndOfStream

    strLine = objTextFile.ReadLine

    If Left(strLine, 7) = "Failure" Then

        strNewText = strNewText & strLine & vbCrLf

    End If

Loop



objTextFile.Close

Set objTextFile = objFSO.OpenTextFile _

    ("test.log", ForWriting)

objTextFile.Write(strNewText)

objTextFile.Close

Skrypt wygląda na nieco skomplikowany, ale to dlatego, że nie ma możliwości bezpośredniej edycji tekstu przy pomocy skryptu. Zamiast tego musimy otworzyć plik tekstowy, odczytać bieżącą zawartość i zamknąć plik. Następnie w pamięci dokonujemy "edycji", raz jeszcze otwieramy plik tekstowy, zastępujemy bieżącą zawartość nowymi danymi i ponownie zamykamy plik. I to właśnie robi ten skrypt.

Po zdefiniowaniu dwóch stałych (ForReading i ForWriting; są to stałe, których będziemy potrzebowali do otwarcia pliku tekstowego) skrypt otwiera do odczytu plik test.log. Tworzymy wówczas pętlę Do (wykonaj), która będzie działać dopóki nie dotrzemy do końca pliku tekstowego; innymi słowy, dopóki nie znajdziemy się na końcu strumienia tekstu.

Co dzieje się wewnątrz tej pętli? Zaczynamy od użycia metody ReadLine do odczytania bieżącego wiersza pliku tekstowego; wiersz ten zostaje przechowany w zmiennej strLine. Następnie sprawdzamy, czy 7 pierwszych liter tworzy słowo Failure; to właśnie robi komenda If Left(strLine, 7) = "Failure". Jeśli 7 pierwszych liter tworzy cokolwiek innego niż Failure, cofamy pętlę z powrotem i odczytujemy następny wiersz.

Co jednak jeśli siedem pierwszych liter tworzy słowo Failure? W takim wypadku mamy inną zmienną – strNewText – której używamy do przechowania tych danych, które chcemy zapisać. Linia kodu strNewText = strNewText & strLine & vbCrLf bierze to, co akurat znajduje się w strNewText, dołącza wartość strLine, a następnie dodaje znak powrotu karetki-przesuwu o wiersz na koniec (vbCrLf). To tworzy w pamięci nowy zestaw danych; kiedy skrypt skończy czytanie całego pliku, strNewText będzie wyglądał tak:

Failure – Operation failed 10/3/2004.

Failure – Operation failed 10/5/2004.

Failure – Operation failed 10/7/2004.

Failure – Operation failed 10/8/2004.

Innymi słowy, po prostu przeczytaliśmy plik i zachowaliśmy listę wszystkich wierszy zaczynających się od Failure; wszystkie wiersze zaczynające się w inny sposób zostały zignorowane.

Teraz gdy mamy już nasz nowy zestaw danych, musimy zamknąć plik tekstowy, a następnie otworzyć go ponownie, tym razem używając stałej ForWriting. (Tak, wiemy, ale tak właśnie działa FileSystemObject: trzeba otworzyć go do odczytu, zamknąć i otworzyć jeszcze raz do modyfikacji.) Mając otwarty plik używamy metody Write by zastąpić istniejącą zawartość pliku test.log wartością naszej nowej zmiennej strNewText. Następnie zamykamy plik, który zapisuje dokonane przez nas zmiany. Efekt? Plik test.log zawiera tylko listę operacji zakończonych niepowodzeniem:

Failure – Operation failed 10/3/2004.

Failure – Operation failed 10/5/2004.

Failure – Operation failed 10/7/2004.

Failure – Operation failed 10/8/2004.

Nieco skomplikowane, ale działa bez zarzutu.

Oczywiście często bywa tak, że słowo, którego szukasz, znajduje się nie na początku, ale gdzieś w środku wiersza. Na przykład, Twój plik dziennika może wyglądać tak:

10/1/2004     Success – Operation succeeded.

10/2/2004     Success – Operation succeeded.

10/3/2004     Failure – Operation failed.

10/4/2004     Success – Operation succeeded.

10/5/2004     Failure – Operation failed.

10/6/2004     Success – Operation succeeded.

10/7/2004     Failure – Operation failed.

10/8/2004     Failure – Operation failed.

W takim wypadku sprawdzenie wartości pierwszych siedmiu znaków nie zda się na wiele; będziesz musiał sprawdzić, czy słowo Failure pojawia się gdziekolwiek w wierszu. Ale to nie problem, możesz użyć funkcji VBScript o nazwie InStr. Przy pomocy InStr przekazujemy do skryptu dwa parametry: ciąg do wyszukiwania (zmienna strLine) oraz element do wyszukiwania słowa Failure. InStr poda w odpowiedzi pozycję znaku, od którego zaczyna się słowo Failure. Na przykład, w poniższym wierszu słowo Failure zaczyna się od znaku 15, wobec czego InStr zwraca właśnie 15:

10/5/2004     Failure – Operation failed.

Jeśli poszukiwanego słowa nie można znaleźć w ciągu, InStr zwróci 0. Tym samym po prostu używamy InStr do sprawdzenia każdego wiersza w poszukiwaniu słowa Failure. Jeśli InStr jest wyższy od 0, oznacza to, że słowo zostało odnalezione. Dodajemy wówczas wiersz do zmiennej strNewText. Oto poprawiona wersja pętli Do, która wyszukuje słowo Failure w dowolnym miejscu wiersza:

Do Until objTextFile.AtEndOfStream

    strLine = objTextFile.ReadLine

    intFailure = InStr(strLine, "Failure")

    If intFailure > 0 Then

        strNewText = strNewText & strLine & vbCrLf

    End If

Loop

Czy mogliśmy użyć tego podejścia wcześniej? Oczywiście. Ale jeśli jesteśmy pewni, że słowo, którego szukamy znajduje się na początku wiersza, użycie funkcji Left wydaje nam się być najlepszym wyborem (podobnie najlepiej jest użyć funkcji Right, jeśli jesteśmy pewni, że poszukiwane słowo znajduje się na końcu wiersza). To dlatego, że można, przynajmniej teoretycznie, "oszukać" funkcję InStr. Na przykład, InStr zidentyfikuje ten wiersz jako oznaczenie niepowodzenia, pomimo, że w rzeczywistości reprezentuje on operację zakończoną sukcesem:

Success – Failure troubleshooter successfully loaded 10/1/2004.

Nie zdarza się to zbyt często, ale po co ryzykować?

PS. Wiemy, że przyjdzie do nas góra listów z pytaniem: "A wyrażenia regularne?" Owszem, przy pomocy wyrażeń regularnych można zrobić bardzo wiele, są one jednak zbyt skomplikowane, by omawiać je w tej rubryce. Wkrótce zajmiemy się wyrażeniami regularnymi, ale w innym miejscu.

 Do początku strony Do początku strony


Centrum skryptów - Systemy operacyjne