Centrum Skrypciarzy - Systemy Operacyjne

Czy można przeanalizować plik rozdzielany znakami tabulacji w taki sposób, aby zapisać go jako plik CSV?

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.

Czy można przeanalizować plik rozdzielany znakami tabulacji w taki sposób, aby zapisać go jako plik CSV?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Czy można przeanalizować plik rozdzielany znakami tabulacji w taki sposób, aby zapisać go jako plik CSV?

-- DM

Cześć Skrypciarze! Odpowiedź

Cześć, DM. Wczoraj rano Skrypciarz piszący te słowa musiał zdrapywać lód z przedniej szyby swojego samochodu. Dziś już jest cieplej – około 6 stopni – ale pada. I chyba to jasne co to oznacza: w Seattle i okolicy sezon baseballa zaczął się na całego!

W przeszłości początek sezonu baseballowego oznaczał zniknięcie Skrypciarza aż do sierpnia. Skrypciarz uważał baseball za coś bardziej interesującego niż praca. (Trudno uwierzyć, ale tak było.) Teraz jednak Skrypciarz musi przyznać, że praca jest znacznie cieplejsza niż baseball. Co oznacza, że zamiast znikać, Skrypciarz ma zamiar siedzieć w swoim przytulnym, ciepłym biurze i zastanawiać się jak przeanalizować plik rozdzielony tabulatorami, a potem zapisać go w formacie CSV.

Zacznijmy od tego, że DM opisuje plik tekstowy rozdzielony znakami tabulacji, który wygląda mniej-więcej tak:

CCre Rec    Name=Jack    Address=5 XYZ Drive    Phone=555-4567

Cre Rec    Name=Jill    Address=7 XYZ Drive    Phone=555-6547

Cre Rec    Name=Jake    Address=9 XYZ Drive    Phone=555-9876

To całkiem sympatyczny plik tekstowy. Ale nie aż tak sympatyczny, jak plik CSV, który DM chciałby mieć.

Name,Address,Phone

"Jack","5 XYZ Drive","555-4567"

"Jill","7 XYZ Drive","555-6547"

"Jake","9 XYZ Drive","555-9876"

Dzisiejsze pytanie brzmi: jak zamienić plik rozdzielony znakami tabulacji na plik CSV? Otóż tak:

Const ForReading = 1



Set objFSO = CreateObject("Scripting.FileSystemObject")

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



Do Until objFile.AtEndOfStream

    strLine = objFile.ReadLine

    arrFields = Split(strLine, vbTab)

    arrName = Split(arrFields(1), "=")

    strName = arrName(1)

    arrAddress = Split(arrFields(2), "=")

    strAddress = arrAddress(1)

    arrPhone = Split(arrFields(3), "=")

    strPhone = arrPhone(1)

    strNewContent = strNewContent & Chr(34) & strName & Chr(34) &  "," & Chr(34) & strAddress & Chr(34) & _

        "," & Chr(34) & strPhone & Chr(34) & vbCrLf

Loop



objFile.Close



Set objFile = objFSO.CreateTextFile("C:\Scripts\Test.csv")



objFile.WriteLine "Name,Address,Phone"

objFile.Write strNewContent



objFile.Close

Zaczynamy, jak widać, definiując stałą o nazwie For Reading i ustawiając jej wartość na 1. Użyjemy jej przy otwarciu naszego pliku rozdzielonego znakami tabulacji. Następnie użyjemy poniższych dwóch wierszy kodu, aby utworzyć obiekt Scripting.FileSystemObject i otworzyć plik C:\Scripts\Test.txt:

Set objFSO = CreateObject("Scripting.FileSystemObject")

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

Co robimy teraz?

Jasne: to my mamy to wiedzieć, nieprawdaż? W porządku, oto jedna z rzeczy, które możemy zrobić: możemy uruchomić pętlę Do Until, która wiersz po wierszu odczyta plik rozdzielony znakami tabulacji. Innymi słowy, tworzymy pętlę Do Until, która działa do momentu, aż własność AtEndOfStream będzie miała wartość True:

Do Until objFile.AtEndOfStream

Wewnątrz pętli, aby przeczytać pierwszą linię pliku i zachować ją w zmiennej nazwanej strLine, używamy tego wiersza kodu:

strLine = objFile.ReadLine

Co to oznacza? Oznacza to, że strLine będzie wyglądać tak:

Cre RecName=JackAddress=5 XYZ DrivePhone=555-4567

Wiele nam to nie daje, musimy jakoś wyłuskać poszczególne wartości dla właściwości Name, Address i Phone. Czy to nie za wiele? Zdecydowanie za wiele. Ale Skrypciarze nigdy się nie poddają!

Najpierw w poniższym wierszu kodu użyjemy funkcji Split do rozdzielenia wartości strLine i utworzenia z niej tablicy:

arrFields = Split(strLine, vbTab)

Rozdzieliwszy wartości z tabulacją jako delimiterem (używając stałej vbTab skryptu VBScript), otrzymujemy tablicę o nazwie arrField, złożoną z następujących pozycji:

  • Cre Rec
  • Name=Jack
  • Address=5 XYZ Drive
  • Phone=555-4567

Dobra. Jak widać, nazwa użytkownika (Jack) jest częścią drugiej pozycji tablicy. (trzeba pamiętać, że pozycje w tablicy są indeksowane od 0, co oznacza, że druga pozycja ma numer indeksu równy 1). Jedynym problemem jest to, że nazwa jest poprzedzona napisem Name=. A zatem pozbądźmy się go:

arrName = Split(arrFields(1), "=")

strName = arrName(1)

Co my tu robimy? W pierwszym wierszu ponownie używamy funkcji Split, aby utworzyć tablicę. Tym razem rozdzielamy wartość pozycji numer 1 (Name=Jack), używając znaku równości (=) jako delimitera. Co nam to daje? Małą, dwuelementową tablicę o nazwie arrName, wyglądającą tak:

  • Name
  • Jack

Idźmy dalej: druga pozycja naszej minitablicy (numer indeksu 1) jest po prostu nazwą użytkownika. Możemy ją zatem pobrać, przypisując wartość pozycji numer 1 do zmiennej strName. To właśnie robimy w drugim wierszu kodu.

Jasne? Powtarzamy procedurę z pozycjami numer 2 (adres) i 3 (numer telefonu) pierwszej macierzy:

arrAddress = Split(arrFields(2), "=")

strAddress = arrAddress(1)

arrPhone = Split(arrFields(3), "=")

strPhone = arrPhone(1)

Mamy teraz trzy zmienne – strName, strAddress oraz strPhone – zawierające informacje pobrane przy analizie pliku tekstowego. Teraz naszym następnym krokiem będzie utworzenie pliku CSV. Użyjemy do tego poniższego, monstrualnego fragmentu kodu:

strNewContent = strNewContent & Chr(34) & strName & Chr(34) &  "," & Chr(34) & strAddress & Chr(34) & _

    "," & Chr(34) & strPhone & Chr(34) & vbCrLf

Nie ma się czego obawiać, nie taki wilk straszny, jak go malują. Przypisujemy tu tylko wartość do zmiennej o nazwie strNewContent. Jaką wartość? Wartość już istniejącą, powiększoną o:

  • Cudzysłów (po to właśnie jest Chr(34)).
  • Wartość zmiennej strName.
  • Kolejny cudzysłów.
  • Przecinek (,)
  • Cudzysłów.
  • Wartość zmiennej strAddress.
  • Cudzysłów.
  • Kolejny przecinek.
  • Cudzysłów.
  • Wartość zmiennej strPhone.
  • Cudzysłów.
  • Znak powrotu karetki (vbCrLf).

Dlaczego ta konstrukcja musi być tak skomplikowana? Dlatego, że staramy się rozwiązać problem elementów zawierających przecinek. Przypuśćmy, że użytkownik nazywa się Ken Myer, Jr. Jeśli wpisalibyśmy tę nazwę bezpośrednio do pliku CSV, to plik przyjąłby, że są to dwie wartości: Ken Myer oraz Jr. Dzieje się tak, gdyż jako delimiter używany jest przecinek. Taki mały szczegół może kompletnie zmienić plik CSV (oraz jakiekolwiek skrypty/aplikacje czytające ten plik). Aby temu zapobiec, ujmujemy każdą wartość w cudzysłów:

"Ken Myer, Jr."

W pliku CSV pozycje ujęte w cudzysłów są traktowane jako pojedyncza wartość, nawet jeśli zawierają przecinek.

Jasne? Robimy to dla Waszego dobra!

Potem wracamy do początku pętli i powtarzamy procedurę dla następnego wiersza pliku rozdzielonego znakami tabulacji.

W momencie, gdy cały plik zostanie przeczytany i przeanalizowany, będziemy gotowi utworzyć plik CSV. Aby to uczynić, najpierw zamykamy plik Test.txt, a następnie tworzymy nowy plik tekstowy o nazwie C:\Scripts\Test.csv, używając tego wiersza kodu:

Set objFile = objFSO.CreateTextFile("C:\Scripts\Test.csv")

DM chce mieć nagłówek, więc pierwszym, co zrobimy z naszym nowym, będzie utworzenie go za pomocą tego wiersza kodu:

objFile.WriteLine "Name,Address,Phone"

Teraz musimy już tylko użyć metody Write, aby wpisać do pliku wartość strNewContent. (A w dalszej kolejności metody Close, aby go zamknąć.) I to wszystko.

Mam nadzieję, że to Ci pomoże, DM. Wygląda to na skomplikowane, ale w rzeczywistości, jeśli się za to weźmiesz i spokojnie przejrzysz, nie jest takie straszne. Mamy nadzieję, że pomogliśmy też innym zmagającym się z tego typu problemami. Wiemy, że są tacy.

 Do początku strony Do początku strony

Centrum Skrypciarzy - Systemy Operacyjne