Centrum skryptów - Systemy operacyjne

Jak zastąpić pojedyncze cudzysłowy 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 zastąpić pojedyncze cudzysłowy w pliku tekstowym?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Czytałem wasz artykuł o zastępowaniu tekstu w pliku tekstowym (j. ang.), i jest to prawie rozwiązanie, którego szukam. Niestety, tekst, który chcę zastąpić to pojedyncze cudzysłowy i nie wiem, jak to zrobić. Jak zastąpić pojedyncze cudzysłowy w pliku tekstowym?

-- JB

Cześć Skrypciarze! Odpowiedź

Cześć, JB. Wiesz, wygląda na to, że będzie to ciężki dzień dla Skrypciarzy. Mamy zebrania rano i wieczorem, dotyczące tak ważnych spraw jak budżet dla Centrum Skryptów. Ale Skrypciarz piszący te słowa zastanawia się przede wszystkim nad inną kwestią – co powinien zjeść na kolację?

Szczerze mówiąc, może to trochę potrwać. W końcu tak ważne decyzje nie powinny być podejmowane pochopnie. Tymczasem poczytaj sobie gazetę. A jeśli żadnej nie masz pod ręką, to przejrzyj poniższy skrypt, zastępujący pojedyncze cudzysłowy w pliku tekstowym. W zasadzie to nie tylko zastępuje on pojedyncze cudzysłowy, ale zastępuje je podwójnymi cudzysłowami! Oto ten skrypt:

Const ForReading = 1

Const ForWriting = 2



Set objFSO = CreateObject("Scripting.FileSystemObject")

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



strText = objFile.ReadAll

objFile.Close



strOldText = Chr(39)

strNewText = Chr(34)



strNewText = Replace(strText, strOldText, strNewText)



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

objFile.WriteLine strNewText

objFile.Close

Zakładamy teraz, że mamy plik tekstowy, który wygląda tak:

'Ken Myer','Finance','Senior Analyst'

'Pilar Ackerman','Human Resources','Manager'

'Jonathan Haas','Transportation','Director'

Chcemy jedynie zastąpić pojedyncze cudzysłowy podwójnymi. Jak odkrył JB, nie jest to jednak takie proste. Dlaczego? Zaraz to wyjaśnimy. Zanim jednak to zrobimy, omówimy pierwszą część skryptu.

Jak widzicie, zaczynamy od zdefiniowania dwóch stałych (ForReading and ForWriting); użyjemy ich gdy otworzymy plik tekstowy. (I tak, musimy otworzyć plik dwukrotnie – raz aby odczytać istniejącą treść i ponownie, aby zapisać nową.) Po zdefiniowaniu stałych, tworzymy wystąpienie Scripting.FileSystemObject, a następnie używamy metody OpenTextFile aby otworzyć plik C:\Scripts\Test.txt do odczytu:

Set objFSO = CreateObject("Scripting.FileSystemObject")

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

Co robimy z plikiem, gdy już go otworzymy? Na początek, używamy metody ReadAll aby odczytać cały plik i przechować jego zawartość w zmiennej o nazwie strText. Następnie zamykamy plik.

Uwaga. Tak, to wydaje się głupie, prawda? Ale FileSystemObject pozwoli nam jedynie otworzyć plik i go odczytać albo otworzyć plik i go zapisać, nie możemy wykonać obu operacji w tym samym czasie (Dziwne ale prawdziwe). Po odczytaniu pliku nie mamy wyboru – musimy go zamknąć zanim będziemy mogli go zapisać.

W typowym skrypcie wyszukiwania i zamiany teraz wywołalibyśmy funkcję Replace VBScript i zastąpili pojedyncze cudzysłowy podwójnymi. Zgadujemy, że JB próbował to zrobić przy pomocy wiersza kodu podobnego do tego:

strNewText = Replace(strText, "'", """)

Składnia wygląda dobrze; w końcu wywołujemy funkcję Replace z trzema parametrami:

  • strText, tekst, na którym chcemy wykonać operację.
  • "'", pojedynczy cudzysłów (wewnątrz podwójnych cudzysłowów), reprezentujący tekst, który chcemy zastąpić.
  • """, podwójny cudzysłów (wewnątrz podwójnych cudzysłowów), reprezentujący tekst, którym chcemy zastąpić.

Jak mówiłem, to wygląda dobrze. Ale oto, co się stanie, jeśli spróbujemy użyć tego kodu:

C:\Scripts\test.vbs(13, 40) Microsoft VBScript compilation error: Unterminated string constant

Auć! O co chodzi?

Jak można się domyślić, problem leży w tym, że zarówno pojedyncze, jak i podwójne cudzysłowy mają specjalne znaczenie w VBScript. Pojedynczy cudzysłów oznacza na przykład komentarz dodany do skryptu:

' This is a comment

Podwójny cudzysłów używany jest zaś między innymi do oznaczania wartości ciągów:

x = "This is a string value."

Jako że te znaki mają specjalne znaczenie, udało nam się jedynie zdezorientować VBScript. Na przykład człowiek może spojrzeć na trzy podwójne cudzysłowy w jednym ciągu i uznać “A, to podwójny codzysłów otoczony przez dwa inne podwójne cudzysłowy.” Niestety VBScript widzi to inaczej; VBScript desperacko próbuje interpretować to wyrażenie przy pomocy wbudowanych zasad analizy kodu. Jedna z tych zasad mówi, że dla każdego otwierającego cudzysłowu musi być zamykający cudzysłów. Innymi słowy, podwójne cudzysłowy muszą chodzić parami. Gdy VBScript widzi nieparzystą liczbę podwójnych cudzysłowów, zakłada, że w jednej z par brakuje cudzysłowu.

Czy to problem? Jasne, że tak: ze względu na błąd składni skrypt nawet się nie skompiluje, nie mówiąc już o uruchomieniu. W taką właśnie sytuację wpakował się JB. Jak obejdziemy ten problem? Jest na to kilka sposobów, ale wybraliśmy następujące podejście:

strOldText = Chr(39)

strNewText = Chr(34)

Używamy tu funkcji Chr aby przydzielić wartości parze zmiennych (strOldText and strNewText). Jeśli przydzielicie Chr wartość całkowitą (na przykład 39), funkcja zwróci znak odpowiadający danej wartości. Zgadnijcie, jaki znak ma wartość ASCII równą 39? Dokładnie: pojedynczy cudzysłów. Jeśli zaś chodzi o wartość ASCII równą 34, to oczywiście jest to podwójny cudzysłów.

Widzicie, co tu robimy? W pierwszym wierszu przydzieliliśmy pojedynczy cudzysłów zmiennej strOldText; to pozwala nam użyć odwołania do pojedynczego cudzysłowu bez używania samego znaku. Potem robimy to samo z podwójnym cudzysłowem. Dlaczego? Bo teraz możemy użyć funkcji Replace przy użyciu nazw zmiennych zamiast problematycznych wyrażeń w rodzaju """:

strNewText = Replace(strText, strOldText, strNewText)

To wyrażenie jest składniowo poprawne. A co ważniejsze, zastąpi wszystkie pojedyncze cudzysłowy podwójnymi.

Uwaga. Skąd wiedzieliśmy, że Chr(39) to pojedynczy cudzysłów, a Chr(34) podwójny? Wierzcie lub nie, ale po prostu to wiedzieliśmy. (Czasami Skrypciarze naprawdę wiedzą o czym mówią... w pewnym sensie) Ale nie musicie wiedzieć, że Chr(39) to pojedynczy cudzysłów; Możecie w każdej chwili sprawdzić wartości ASCII w VBScript Language Reference.

Reszta skryptu praktycznie sama się pisze. Po ponownym otwarciu Test.txt (tym razem do zapisu) wywołujemy metodę Write i zastępujemy istniejącą zawartość pliku nową (przechowywaną w zmiennej strNewText). Następnie zamykamy plik tekstowy i wracamy do planowania dzisiejszej kolacji. Czy ktoś jeszcze ma ochotę na pieczywo czosnkowe?

Gdy skrypt zrobi swoje, plik tekstowy będzie wyglądał tak:

"Ken Myer","Finance","Senior Analyst"

"Pilar Ackerman","Human Resources","Manager"

"Jonathan Haas","Transportation","Director"

Czyli dokładnie tak, jak chcemy.

Jako że dzisiejszy artykuł jest już skończony, a kolacja zaplanowana. Czas przejść do naszego pierwszego zebrania, dotyczącego budżetu. W zeszłym roku po raz pierwszy Skrpyciarze rzeczywiście dostali budżet. Wzięliśmy wszystkie te pieniądze i natychmiast wydaliśmy je wszystkie na lalki Dr. Scripto Bobblehead. Tegoroczne zebranie budżetowe na pewno również będzie ciekawe.

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne