Jak zastąpić tekst zawierający podwójne cudzysłowy i znak tabulacji?
Skrypciarze odpowiadają na Wasze pytania
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ć tekst zawierający podwójne cudzysłowy i znak tabulacji?
Cześć, Skrypciarze! Jeden z Waszych artykułów na temat zastępowania tekstu w pliku okazał się bardzo przydatny. Potrzebowałbym jednak czegoś bardziej zaawansowanego: chciałbym zastąpić tekst zawierający podwójne cudzysłowy i znak tabulacji. Jak to zrobić?
-- FC
Cześć, FC! Po Twoim pytaniu mniemam, że czytałeś już kiedyś jakiś artykuł z serii „Cześć, Skrypciarze!”. Zauważyłeś więc na pewno, że dzielę się na łamach dość osobistymi spostrzeżeniami, których, niestety, nikt nie podziela. O jakiego typu spostrzeżenia chodzi mi obecnie? No na przykład karty rabatowe w sklepach spożywczych. Nie wiem na ile Ty, FC, obeznany jesteś z tym procederem, ale w Stanach jest to bardzo popularne. Kupując w danym sklepie okazujesz kartę rabatową i… dostajesz rabat. Czy mam coś przeciwko rabatom? Oczywiście, że nie mam, nie podoba mi się jednak fakt, że sklep wie co kupuję i w jakich ilościach. Zakupy są przecież sprawą dość osobistą i nie chcę doczekać czasów, kiedy informacja na temat co i gdzie kupuję będzie dostępna online.
Na szczęście tajność informacji nie dotyczy pytań na temat zastępowania tekstu zawierającego podwójne cudzysłowy i znak tabulacji. Takiej informacji udzielamy publicznie i może dorzucimy coś jeszcze w formie rabatu…
Z tego co napisałeś, FC, wynika, że masz plik (lub kilka plików), które zawierają tekst, w którym podkreślnik oznacza znak tabulacji:
rowsep="1">_
Ty natomiast chciałbyś zastąpić te wartości następującymi:
rowsep="1"><para>
Napotykam tu jednak mały problem, a w sumie dwa. Po pierwsze: podwójne cudzysłowy w ciągu docelowym, po drugie: znak tabulacji pod koniec tego ciągu. Jak wyszukać tekst zawierający podwójny cudzysłów i znak tabulacji? No cóż, jest jeden sposób:
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
strTargetText = "rowsep=" & Chr(34) & "1" & Chr(34) & ">" & vbTab
strReplacementText = "rowsep=" & Chr(34) & "1" & Chr(34) & "><para>"
strNewText = Replace(strText, strTargetText, strReplacementText)
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForWriting)
objFile.WriteLine strNewText
objFile.Close
Zobaczmy, czy jesteśmy w stanie wytłumaczyć, jak działa nasz skrypt. Jak widać, zaczynamy w sposób dość standardowy – od zdefiniowania pary stałych ForReading oraz ForWriting. Będziemy używać ich do otwierania naszych plików tekstowych – stałej ForReading do otworzenia pliku i przeczytania zawartości, a następnie stałej ForWriting do ponownego otworzenia pliku zmiany pierwotnej zawartości na wartość docelową.
Uwaga: Może to i wydaje się głupie, że nie możemy zmodyfikować pliku przy użyciu jednej operacji, tylko trzeba go otworzyć, wpisać zawartość do pamięci, następnie zamknąć plik. I to nie wszystko. Po dokonaniu zmian w kopii roboczej musimy ponownie otworzyć plik i zastąpić zawartość pierwotną naszą kopią roboczą. |
Po zdefiniowaniu naszych dwóch stałych, tworzymy wystąpienie obiektu Scripting.FileSystemObject, a następnie używamy poniższego wiersza kodu w celu otworzenia pliku C:\Scripts\Test.txt do odczytu:
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)
Po otworzeniu pliku korzystamy z metody ReadAll w celu sczytania całej zawartości pliku, przechowując jego zawartość w zmiennej strText. Po sczytaniu pliku wywołujemy metodę Close (bez obaw, wspominaliśmy przecież, że w odpowiednim czasie tworzymy plik po raz kolejny).
To wszystko sprowadza nas do następujących dwóch wierszy kodu:
strTargetText = "rowsep=" & Chr(34) & "1" & Chr(34) & ">" & vbTab
strReplacementText = "rowsep=" & Chr(34) & "1" & Chr(34) & "><para>"
Wygląda strasznie, przyznaję, nie taki diabeł jednak straszny jak go malują. W pierwszym wierszu po prostu definiujemy tekst, który chcemy wyszukać, a jak dobrze pamiętacie wygląda on następująco:
rowsep="1">_
Pracowanie z takim tekstem może być niezmiernie… hmm… ciekawe. Dopóki nie spróbujesz, możesz jeszcze się łudzić, że można po prostu przypisać tę wartość zmiennej przy użyciu następującego kodu:
strTargetText = "rowsep="1"> "
Teraz nie jest to już ciekawe, ale frustrujące, ponieważ odkrywasz, że takiej operacji nie można po prostu wykonać, a to z dwóch następujących powodów:
- Problemów nastręczają podwójne cudzysłowy wewnątrz ciągu. Dlaczego? Ponieważ VBScript używa tych znaków w celu zaznaczenia początku i końca ciągu. Dlatego też dla VBScript naszym ciągiem jest: "rowsep=". Po odkryciu kolejnych cudzysłowów skrypt głupieje i następuje błąd.
- Podczas przypisywania wartości do ciągu znakowego tak naprawdę znak tabulacji nie zostaje przypisany – w jego miejsce przypisanych zostaje pięć spacji. Wyglądają może i tak samo, ale to tylko pozory.
Innymi słowy, aby przypisać tekst docelowy zmiennej strTargetText, musimy oba te problemy jakoś obejść. Nasze rozwiązanie składa się z czterech składowych ciągu:
- rozpoczęcia podwójnym cudzysłowem (").
- Wartości ciągu rowsep=.
- Funkcji Chr(34). Chr(34) to właściwie reprezentacja podwójnego cudzysłowu w ASCII. Oznacza to, że dodajemy po prostu Chr(34) do naszego ciągu, bez potrzeby wpisywania podwójnego cudzysłowu. Omijamy tym samym problem związany z umieszczaniem jednego cudzysłowu w drugim (tak, istnieją również inne sposoby na umieszczanie cudzysłowu w cudzysłowie, ten jednak jest najprostszy).
- Wartości ciągu 1.
- Kolejnego wystąpienia Chr(34). Innymi słowy, kolejny zestaw podwójnych cudzysłowów.
- Wartości ciągu >.
- Znaku tabulacji, który w VBScript ma stałą vbTab. Nie musimy przypominać, że nasz ciąg zawiera znak tabulacji. Pamiętajcie więc, żeby nie dodawać go za pomocą klawisza TAB, ale za pomocą vbTab.
- Zamykający cudzysłów (").
Bardziej wizualnie, z podkreślnikiem w roli znaku tabulacji oraz prawdziwymi cudzysłowami w miejsce wartości Chr(34):
"
+ rowsep=
+ "
+ 1
+ "
+ >
+ _
+ "
_____________________
"rowsep="1">_"
Dzisiejszy skrypt, jak sami widzicie, sponsorują literki Chr(34) oraz vbTab.
Po skonstruowaniu naszego ciągu przypisujemy jego wartość zmiennej strTargetText, a następnie korzystamy z podobnego podejścia w celu skonstruowania tekstu zastępczego:
strReplacementText = "rowsep=" & Chr(34) & "1" & Chr(34) & "><para>"
Jedyną różnicą jest tu, że na końcu mamy nie znak tabulacji, ale wartość ciągu <para>.
Uwaga: Czy nie łatwiej byłoby wyszukać wszystkie znaki tabulacji i zastąpić je ciągiem <para>? Tak, ale tylko jeżeli chcielibyśmy zastąpić wszystkie znaki tabulacji, a z tego, co napisał FC, wnioskuję, że chodziło mu o jakieś konkretne znaki tabulacji (które występują po rowsep="1"). Właśnie dlatego skorzystaliśmy z tego bardziej skomplikowanego, ale i pewniejszego sposobu. |
Po zdefiniowaniu naszego tekstu docelowego i tekstu, którym mamy go zastąpić, wystarczy już tylko wywołać funkcję Replace:
strNewText = Replace(strText, strTargetText, strReplacementText)
To polecenie wyszuka wystąpienia tekstu docelowego dla wartości strText, a następnie je zastąpi. Po dokonaniu tego, nasz zmodyfikowany plik tekstowy (lub przynajmniej nasza kopia robocza tego pliku tekstowego) zostanie przypisany zmiennej strNewText.
Oczywiście zmodyfikowaliśmy tu tylko kopię roboczą. W celu zmodyfikowania tekstu właściwego musimy skorzystać z następującego fragmentu kodu:
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForWriting)
objFile.WriteLine strNewText
objFile.Close
W pierwszym wierszu otwieramy ponownie plik C:\Scripts\Test.txt, tym razem do zapisu. W drugim wierszu przechodzimy do właściwego zapisywania, korzystając z WriteLine (przypisujemy wartość naszego zmodyfikowanego pliku roboczego strNewText zmiennej Test.txt. W końcu, w trzecim wierszu, wywołujemy metodę Close i zamykamy plik. Teraz już naprawdę skończyliśmy, a tekst docelowy w pliku Test.txt został również zamieniony.
Obiecywałem w sumie jakiś rabat, ale artykuł jest już dość długi, rabatem może będzie więc nie dodawanie już niczego i pozwolenie Ci, FC, spokojnie pójść na zakupy… Uważaj tylko z kartami rabatowymi. Wielki brat czuwa…
Do początku strony |