Centrum skryptów - Systemy operacyjne

Jak wyodrębnić cały tekst pomiędzy dwoma tagami 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 wyodrębnić cały tekst pomiędzy dwoma tagami w pliku tekstowym?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Mam wiele plików tekstowym w folderze. Muszę otworzyć każdy z nich, pobrać wszystko, co się znajduje pomiędzy tagami <filecount> oraz </filecount>, a następnie zapisać te informacje w oddzielnym pliku. Jak to zrobić?

-- RP

Cześć Skrypciarze! Odpowiedź

Cześć, RP. Jakoś tak się złożyło, że któregoś wieczoru rozpocząłem dyskusję z moim synem na temat naszej podróży do Barcelony na forum informatyczne TechEd IT Forum 2007. „Nadal tego nie rozumiem” – powiedział mój syn – „dlaczego ktoś chciałby z wami rozmawiać?”

„No cóż” – odpowiedziałem – „chyba dlatego, że jesteśmy sławni.”

„Nie, nie jesteście” - odpowiedział mój syn – „gdybyście byli sławni, bylibyście w Wikipedii.”

I wiecie co? On chyba ma rację. Gdyby Skrypciarze byli sławni, mieliby swój artykuł w Wikipedii. A jednak nie mają. Czy to może oznaczać, że być może Skrypciarze nie są wcale tak sławni i ważni, jak im samym się wydaje?

Nie, oczywiście, że nie; oznacza to, że Skrypciarze, którzy z natury są skromni i niewymagający, nie ujawnili na swój temat wystarczająco dużo informacji, aby ktoś mógłby napisać na ich temat artykuł w Wikipedii. Oczywiście, sami moglibyśmy napisać artykuł na swój temat, ale to nie brzmi zbyt szlachetnie. Dlatego też, jeżeli ktoś z Was jest zainteresowany napisaniem takiego artykułu, byłoby nam bardzo miło. W końcu któż mógłby zrobić to lepiej, niż nasi wierni czytelnicy, którzy znają nas przecież na wylot.

Myślę, że wasze informacje na nasz temat to więcej, niż potrzeba do artykułu w Wikipedii. Gdyby jednak ktoś miał zastrzeżenia, wystarczy wspomnieć, że właśnie Skrypciarze wymyślili skrypt, który może pobrać tekst znajdujący się pomiędzy tagami w pliku tekstowym.

Pokażemy Wam skrypt, który zrobi to w jednym pliku, a potem jeszcze jeden skrypt, który może pobrać te informacje z każdego pliku w folderze.

Oto ten podstawowy:

Const ForReading = 1



Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)



strContents = objFile.ReadAll

objFile.Close



strStartText = "<filecount>"

strEndText = "</filecount>"



intStart = InStr(strContents, strStartText)

intStart = intStart + Len(strStartText)



intEnd = InStr(strContents, strEndText)



intCharacters = intEnd - intStart



strText = Mid(strContents, intStart, intCharacters)



Wscript.Echo strText

Dobra, przyznaję, wygląda on trochę bzdurnie, ale obiecuję, że wszystko pięknie zdebzdurzę, zanim skończymy.

Uwaga. Tak, „zdebzdurzyć” to słowo bardzo techniczne, którego tylko osoba naprawdę sławna i zasługująca na uznanie w encyklopedii online mogłaby użyć.

I to użyć właściwie.

Na początek, zdefiniujemy stałą i nazwie ForReading i nadamy jej wartość 1; zastosujemy tę stałą podczas otwierania naszego pliku tekstowego. Następnie tworzymy wystąpienie obiektu Scripting.FileSystemObject i zastosujemy metodę OpenTextFile w celu otwarcia pliku C:\Scripts\Test.txt do odczytu:

Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)

Co zrobimy z tym plikiem, kiedy już go otworzymy? No cóż, prawdę mówiąc niewiele: po prostu wywołamy metodę ReadAll w celu wczytania zawartości do zmiennej o nazwie strContents, potem wywołujemy metodę Close, aby natychmiast zamknąć plik.

Bez obaw; kiedy mamy zawartość pliku zachowaną w pamięci nie będziemy potrzebować więcej tego pliku. Naprawdę, czy ja Was kiedykolwiek okłamałem?

RP chce wyodrębnić cały tekst pomiędzy tagami <filecount> oraz </filecount>. Nie wiem na pewno, jak wygląda plik RP, zatem zastosuję przykładowy plik:

<filename>Test.txt</filename>

<filedate>10/23/2007</filedate>

<filecount>786</filecount>

<filelocation>C:\Scripts</filelocation>

Chciałbym zauważyć, że zakładam, że te dwa docelowe tagi pojawiają się w każdym pliku tylko raz. Czy ten skrypt zadziała, jeżeli tagi pojawią się więcej niż raz? Nie. Ale może w niedalekiej przyszłości napiszę następny artykuł, a w nim znajdziecie odpowiedni skrypt. A może nie. Gwiazdy mają swoje kaprysy.

Powinienem także zauważyć, że istotne jest, iż nasz skrypt zadziała niezależnie od tego, jak wygląda ten plik. Załóżmy, że plik wyglądał tak:

<filename>Test.txt</filename><filedate>10/23/2007

</filedate><filecount>786</filecount><filelocation>

C:\Scripts</filelocation>

Żaden problem; w dalszym ciągu skrypt będzie mógł pobrać tekst znajdujący się pomiędzy docelowymi tagami. Nawet, gdy tekst będzie wyglądał tak:

<filename>Test.txt</filename><filedate>10/23/2007

</filedate><filecount>786

</filecount><filelocation>C:\Scripts</filelocation>

Naszym następnym krokiem jest przypisanie naszych dwóch tagów do pary zmiennych, jednej o nazwie strStartText, a drugiej o nazwie strEndText:

strStartText = "<filecount>"

strEndText = "</filecount>"

Teraz przechodzimy do poniższego fragmentu kodu:

intStart = InStr(strContents, strStartText)

intStart = intStart + Len(strStartText)

Co się tutaj dzieje? Cóż, w pierwszym wierszu stosujemy funkcję InStr w celu określenia pozycji znaku, od której zaczyna się tag <filecount> ; w naszym przykładowym pliku tekstowym będzie to pozycja znaku 65. W drugim wierszu dodajemy długość tagu <filecount> (czyli liczbę znaków tagu) do tej wartości. Długość tagu to 11, co dodane do 65 daje ostateczną wartość zmiennej intStart równą 76. Oznacza to także, że nasz docelowy tekst rozpocznie się na pozycji znaku 76.

Jeżeli to trochę za bardzo skomplikowane, spójrzcie na poniższą tabelę. Zmapowaliśmy w niej pozycje od 65 do 75. Jak widać, jeżeli tag <filecount> zaczyna się na pozycji znaku 65, to kończy na pozycji znaku 75:

65 66 67 68 69 70 71 72 73 74 75
< f i l e c o u n t >

A to oznacza, że tekst, który chcemy wyodrębnić musi się zacząć na pozycji znaku 76.

Następnie stosujemy poniższy wiersz kodu w celu określenia początku drugiego tagu </filecount>):

intEnd = InStr(strContents, strEndText)

W naszym przykładowym skrypcie jest to pozycja znaku 79.

Zbliżamy się do sedna. Naszym następnym krokiem jest określenie liczby znaków, które chcemy wyodrębnić. Możemy obliczyć tę wartość odejmując pozycję początkową naszego docelowego tekstu (76) od początkowej pozycji tagu zamykającego (</filecount>):

intCharacters = intEnd - intStart

Co nam to daje? To nam daje 79 minus 76, czyli 3. Cyfra 3 to właśnie liczba znaków znajdujących się pomiędzy tymi tagami.

Kiedy już ją znamy, możemy wywołać funkcję Mid i wyodrębnić te znaki:

strText = Mid(strContents, intStart, intCharacters)

Dzięki temu skrypt wykorzysta wartość zmiennej strContents i począwszy od pozycji początkowej 76 (intStart) przejdzie przez 3 znaki (intCharacters), zgarniając po drodze każdy znak. Co dokładnie zgarniemy? To, co następuje:

786

Niezłe, prawda?

Teraz, niestety bez żadnych dodatkowych wyjaśnień, przedstawiam skrypt, który może wyodrębnić tekst z wszystkich plików tekstowych w folderze, wpisując otrzymaną zawartość do pliku o nazwie Totals.txt:

Const ForReading = 1



Set objFSO = CreateObject("Scripting.FileSystemObject")

strComputer = "."



Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



Set colFiles = objWMIService.ExecQuery _

    ("ASSOCIATORS OF {Win32_Directory.Name='C:\Scripts'} Where " _

        & "ResultClass = CIM_DataFile")



For Each objFile In colFiles

    Set objFile = objFSO.OpenTextFile(objFile.Name, ForReading)



    strContents = objFile.ReadAll

    objFile.Close



    strStartText = "<filecount>"

    strEndText = "</filecount>"



    intStart = InStr(strContents, strStartText)

    intStart = intStart + Len(strStartText)



    intEnd = InStr(strContents, strEndText)



    intCharacters = intEnd - intStart

    strCount =  Mid(strContents, intStart, intCharacters)



    strText = strtext & strCount & vbCrLf

Next



Set objFile = objFSO.CreateTextFile("C:\Scripts\Totals.txt")



objFile.Write strText

objFile.Close

Czy on naprawdę zadziała? Sami spróbujcie.

Jeżeli myślicie poważnie o utworzeniu nowego artykułu w Wikipedii na temat Skrypciarzy, powinienem zwrócić Waszą uwagę na fakt, iż Wikipedia zabrania wpisywania „bzdur patentowanych”. Poza tym piszcie, co chcecie, tylko nie przepisujcie całych artykułów naszej rubryki.

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne