Spis treści Skorowidz Poziom główny Poziom nadrzędny Wstecz Dalej Zadania ©

Edytory i edycja plików znakowych

Wprowadzenie

Edytory plików znakowych służą do tworzenia i modyfikacji zawartości plików znakowych. Interaktywne edytory ekranowe są przeznaczone do wykonywania poleceń operatora, który przekazuje je za pomocą urządzeń konsoli (klawiatura, mysz), widząc na monitorze zawartość redagowanego tekstu. Z edytorów tego typu korzystają wszyscy użytkownicy systemów komputerowych: autorzy dokumentów, operatorzy przygotowujący zestawy danych, programiści, administratorzy systemów itd. System Windows jest domyślnie wyposażony w edytory notepad i edit. W systemach UNIX podstawowy systemowy edytor plików znakowych nosi nazwę vi, dostępne są także inne edytory.

Redagowanie plików znakowych jest ważną czynnością, i służy do niej wiele rodzajów wyspecjalizowanego oprogramowania. I tak, edytory programistyczne są zorientowane na tworzenie kodu źródłowego programów, i zazwyczaj są sprzężone ze środowiskami do ich uruchamiania. Edytory kodu źródłowego dokumentów są wyposażone w funkcje ułatwiające wprowadzanie dyrektyw formatowania w wybranym języku. Edytory uniwersalne (takie jak emacs, vi, scite, mcedit) umożliwiają pracę z tekstem ciągłym, zbiorami danych lub kodem źródłowym programów albo dokumentów.

Osobna klasa programów, zwanych przeglądarkami plików (należą do nich np. przeglądarka stronicująca less i przeglądarki internetowe), pozwala przeglądać zawartość plików i wyszukiwać w nich informacje, jednak bez możliwości wprowadzania zmian.

Współczesne edytory nie operują bezpośrednio na zawartości pliku, tylko na kopii jego zawartości umieszczonej w pamięci operacyjnej. Obszar pamięci zawierający taką kopię często określa się mianem bufora. W dawnych edytorach bufor przechowywał zawartość pojedynczego wiersza pliku; obecnie bufor z reguły odpowiada zawartości całego pliku. Wiele współczesnych edytorów jest w stanie obsługiwać jednocześnie wiele buforów, z których każdy odpowiada innemu plikowi. Umieszczenie kopii pliku w buforze zwane bywa otwarciem pliku (open); umieszczenie bieżącej zawartości bufora w pliku to zapisanie pliku (save). Zapis bywa zazwyczaj dokonywany jedynie na żądanie operatora, choć niektóre edytory zapisują bufor automatycznie w regularnych odstępach czasu. Skasowanie bufora określa się jako zamknięcie pliku (close). W przypadku edytorów interaktywnych, operacjom na buforach pamięci towarzyszą analogiczne operacje na oknach edycyjnych widocznych w środowisku użytkownika.

Załączona ilustracja przedstawia zrzuty ekranowe interaktywnych edytorów plików znakowych z różnych środowisk.

Konwencje zapisu stosowane w plikach znakowych

Znaki sterujące

W plikach znakowych każdy znak zapisu tłumaczy się na jeden graficzny znak wydruku. Nie ma możliwości nadania tekstowi żadnej struktury (choćby ciągu akapitów lub tabeli) ani właściwości wizualnych (takich jak określenie kroju pisma lub barwy tekstu). Do oddzielania elementów tekstu ciągłego lub danych tabelarycznych służą poniższe znaki:

Konwencja ta jest specyficzna dla plików znakowych. W środowiskach dysponujących bogatszym zestawem środków formatowania może okazać się, że powyższe zasady są nieaktualne, a ich stosowanie utrudnia efektywną pracę.

Interpunkcja i pisownia

Przed przystąpieniem do tworzenia notatek i dokumentów zawierających tekst ciągły warto przypomnieć sobie podstawowe zasady interpunkcji i pisowni. Zasady te odnoszą się w równym stopniu do tekstów przechowywanych w postaci papierowej i elektronicznej. W przyszłości uzupełnimy je zasadami związanymi z wykorzystaniem znaków typowo typograficznych.

Tryby edycji interaktywnej

Tryb wstawiania (insert) domyślnie obowiązuje w większości edytorów interaktywnych. W tym trybie nowo wprowadzone znaki są umieszczane między znakami poprzednio wprowadzonymi, w miejscu wskazanym pozycją kursora. Przy pisaniu w trybie wstawiania tekst zwiększa swoją objętość.

Tryb nadpisywania (overwrite) jest dostępny w większości edytorów interaktywnych. Polega on na zastępowaniu znaku wskazanego przez kursor znakiem nowo wprowadzanym. Bywa wygodny przy aktualizacji i poprawie tekstów, tabel i zbiorów danych.

Przełącznikiem trybów wstawiania i nadpisywania jest zazwyczaj klawisz Insert. Wiele edytorów sygnalizuje użytkownikowi tryb, w jakim aktualnie się znajduje, np. za pomocą kształtu kursora.

(Tryb Insert)(Tryb Overwrite)
-- Były sobie raz trzy siostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...
-- Były sobie raz trzy siostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...
Wprowadzenie znaku S
-- Były sobie raz trzy Ssiostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...
-- Były sobie raz trzy Siostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...

Oto inne powszechnie spotykane rozwiązanie kształtów kursora.

-- Były sobie raz trzy siostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...
-- Były sobie raz trzy siostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...
Wprowadzenie znaku S
-- Były sobie raz trzy Ssiostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...
-- Były sobie raz trzy Siostrzyczki↵
rozpoczął Suseł z wielkim pośpiechem...

Aktualny tryb edycji bywa też sygnalizowany za pomocą znacznika w wierszu statusu okna edytora.

Polecenie edycyjne Backspace (związane z klawiszem o tej samej nazwie) usuwa znak położony bezpośrednio przed znakiem bieżącym („na lewo” od kursora) i zmniejsza o 1 numer znaku bieżącego (przesuwa kursor w lewo; znak bieżący pozostaje ten sam).

-- Były sobie raz trzy siostrzyczki -- rozpoczął Suseł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Backspace

-- Były sobie raz trzy siostrzyczki -- rozpocząłSuseł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Backspace

-- Były sobie raz trzy siostrzyczki -- rozpocząSuseł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Polecenie edycyjne Delete (związane z klawiszem o tej samej nazwie) usuwa znak bieżący („na prawo” od kursora lub wskazany przez kursor, zależnie od postaci graficznej kursora).

-- Były sobie raz trzy siostrzyczki -- rozpoczął Suseł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Delete

-- Były sobie raz trzy siostrzyczki -- rozpoczął useł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Delete

-- Były sobie raz trzy siostrzyczki -- rozpoczął seł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Delete ↓ …

Znaki niedrukowalne (tzw. „białe”): spacje, znaki tabulacji i znaki końca wiersza, są takimi samymi znakami, jak wszystkie inne, choć mają mniej typową postać graficzną. W szczególności można je usuwać poleceniami Backspace.

-- Były sobie raz trzy siostrzyczki -- rozpoczął Suseł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Backspace

-- Były sobie raz trzy siostrzyczki -- rozpoczął Suseł↵
zwielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Backspace

-- Były sobie raz trzy siostrzyczki -- rozpoczął Suseł↵
wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Backspace

-- Były sobie raz trzy siostrzyczki -- rozpoczął Susełwielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Backspace

-- Były sobie raz trzy siostrzyczki -- rozpoczął Susewielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Ten sam skutek można wymusić także posługując się komendą Delete.

Delete

-- Były sobie raz trzy siostrzyczki -- rozpoczął eł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Delete

-- Były sobie raz trzy siostrzyczki -- rozpoczął ł↵
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Delete

-- Były sobie raz trzy siostrzyczki -- rozpoczął 
z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Delete

-- Były sobie raz trzy siostrzyczki -- rozpoczął z wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Delete

-- Były sobie raz trzy siostrzyczki -- rozpoczął  wielkim pośpiechem -- a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Operacje na blokach tekstu

Wiele edytorów interaktywnych umożliwia wykonanie wskazanej operacji edycyjnej na całym tekście lub na jego wyróżnionym fragmencie, zwanym blokiem. Blok oznacza się poprzez wskazanie położenia znacznika początku bloku i znacznika końca bloku.

Do zaznaczania bloku może służyć klawiatura, mysz lub specjalne polecenia. W wielu współczesnych programach edycyjnych wykorzystuje się w tym celu lewy przycisk myszy we współpracy z jej kursorem oraz klawisze strzałek w połączeniu z klawiszem Shift, we współpracy z kursorem tekstowym. Zaawansowane edytory dają również możliwość wyróżnienia jako bloku pojedynczego słowa, bieżącego wiersza, całości wyrażenia umieszczonego w nawiasach itp.

Typowe operacje możliwe do wykonania na bloku to:

Zaawansowane edytory (w tym np. emacs, scite i częściowo vp) umożliwiają także inne operacje blokowe, jak np. wcięcie poziome bloku (polegające na dopisaniu lub usunięciu ustalonej liczby białych znaków na początku każdego wiersza), sklejenie całego bloku w jeden wiersz (polegające na zastąpieniu wszystkich znaków końca wiersza znakami spacji), czy też sformatowanie (to znaczy podzielenie na wiersze o zadanej szerokości).

W zaawansowanych edytorach możliwe jest także przetworzenie bloku za pomocą zewnętrznego programu. Polega ono na zastąpieniu bieżącej zawartości bloku ciągiem znaków uzyskanym w wyniku wykonania pewnej zewnętrznej operacji. Może ona wiązać np. z poprawą ortografii, usunięciem lub dodaniem odstępów, zastąpieniem poleceń efektem ich wykonania itp.

Operacjom blokowym można poddawać bloki sekwencyjne i bloki prostokątne.

Bloki sekwencyjne

Blok sekwencyjny stanowi zespół wszystkich znaków pliku zawartych między znacznikami początku i końca bloku. Obejmuje on więc końcowy fragment wiersza tekstu wskazywanego przez znacznik początku bloku, a dalej pełne wiersze tekstu (ze znakami końców wierszy włącznie!), z być może niepełnym początkowym fragmentem wiersza wskazywanego przez znacznik końca bloku.

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵
Znaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytora↵
znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


Jeżeli zależy nam na przetwarzaniu (powielaniu, usuwaniu) kompletnych wierszy pliku, to warto zadbać o to, by znacznik końca bloku znajdował się za znakiem końca wiersza, czyli bezpośrednio na początku wiersza następnego. Wtedy znak końca wiersza będzie należał do bloku i nie trzeba go będzie uzupełniać ręcznie:

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵
Znaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytora↵
znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


Usunięcie takiego bloku doprowadzi do następującej sytuacji:

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵
znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


zaś powielając go, dostaniemy

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵
Znaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytora↵
Znaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytora↵
znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


Sytuacja taka jest na ogół pożądana (zwłaszcza jeżeli plik zawiera tabelę danych, w której znaki końca wiersza pełnią rolę separatora rekordów).

Ponieważ znak końca wiersza zwykle jest niewidoczny, wiele osób oznacza zespół wierszy następująco:

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵
Znaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytora
znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


W tej sytuacji znak końca ostatniego wiersza nie jest włączony do bloku i nie będzie razem z nim kopiowany, usuwany, zapamiętywany itp. Na przykład po usunięciu bloku pozostanie pusty wiersz:

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵

znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


mimo że nie jest nam potrzebny, zaś po powieleniu bloku dostaniemy dwa wiersze złączone ze sobą:

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵
Znaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytoraZnaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytora
znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


i prawdopodobnie będziemy je musieli rozdzielić, wstawiając ręcznie znak końca wiersza.

Bloki kolumnowe

Blok kolumnowy (inaczej: prostokątny) obejmuje tylko fragmenty wierszy. Znaczniki początku i końca bloku stanowią narożniki prostokąta, do którego należą tylko znaki z oznaczonych wierszy i oznaczonych kolumn pliku. (Plik znakowy dzieli się na wiersze, lecz nie dzieli się na kolumny; kolumnę stanowią znaki zajmujące tę samą pozycję — na przykład czwartą — w kolejnych wierszach).

Blok jest wyznaczany za pomocą znaczników początku i końca bloku.↵
Znaczniki te można ustawiać wydając odpowiednie komendy,↵
np. ustawiając kursor znakowy i wciskając w pewnej kolejności↵
klawisze lub używając myszy. Zależnie od trybu działania edytora↵
znaczniki będą traktowane albo jako początek i koniec ciągu znaków↵
(blok sekwencyjny), albo jako naroża prostokąta (blok prostokątny).↵


Najprostsze edytory plików znakowych (np. notepad) obsługują tylko bloki sekwencyjne. Edytory bardziej rozbudowane (np. emacs, scite, gvim lub vp) umożliwiają pracę z blokami obu typów.

Wyszukiwanie i zamiana znaków i fraz w treści pliku

Wyszukiwanie fraz w danym ciągu znaków nie jest ściśle związane z redagowaniem pliku, ale bardzo często się podczas przydaje podczas prac edycyjnych. Dlatego edytory użytkowe, oprócz możliwości bezpośredniego wprowadzania i usuwania znaków tekstu, umożliwiają zazwyczaj znalezienie w tekście żądanej frazy oraz zamianę wystąpień pewnej frazy inną frazą. Zamiana fraz jest czynnością redakcyjną, gdyż ingeruje w zawartość tekstu. Wymienione funkcje są realizowane w różnych typach oprogramowania, nie zawsze związanych z redagowaniem treści pliku i niekoniecznie interaktywnych.

W edytorach interaktywnych funkcje te są na ogół realizowane za pośrednictwem formularzy dialogowych. Efekt wyszukiwania polega wtedy najczęściej na ustawieniu kursora w miejscu wystąpienia poszukiwanego ciągu znaków, czasami znaleziony ciąg jest wyróżniany jako blok. Niektóre środowiska umożliwiają również jednoczesne oznaczenie wszystkich miejsc, w których występuje wskazany ciąg znaków.

Typowy formularz obsługujący funkcję wyszukiwania we współczesnym edytorze rozpoczyna akcję wyszukiwania po zatwierdzeniu. Możliwe jest również inne podejście, zwane wyszukiwaniem przyrostowym. Jest ono stosowane zwłaszcza przy przeglądaniu długich list, np. w spisach plików lub w tabelach danych, ale bywa wygodne także w odniesieniu do tekstu ciągłego. Miejsce wystąpienia frazy zaznaczane jest wtedy na bieżąco, w miarę wpisywania ciągu znaków do formularza.

Załączony zestaw ilustracji przedstawia kilka interfejsów wyszukiwania fraz w plikach rozmaitych formatów. Przykłady pochodzą z różnych systemów i środowisk.

W dalszej części bieżącego rozdziału dużo uwagi poświęcimy regułom opisującym złożone wzorce wyszukiwania, a następnie zamianie fraz. Narzędzia te pozwalają na sprawne wykonanie wielu mechanicznych prac, zwłaszcza podczas przygotowywania plików danych.

Kontekst występowania wyrażeń

Często mamy do czynienia z sytuacją, w której dane wyrażenie interesuje nas jedynie wtedy, kiedy jego wystąpieniu towarzyszą dodatkowe okoliczności. Okoliczności te zwykle opisuje się formułując wymagania co do wyrażeń bezpośrednio sąsiadujących z interesującą nas frazą, czyli tzw. kontekstu.

Na przykład w tekście Karolina złapała 13 myszy w ciągu ostatnich 13 godzin (Karolina to kotka, nie człowiek) ciąg znaków Karol, który innych sytuacjach mógłby być traktowany jako słowo, a nawet jako imię, nie jest słowem, gdyż w jego bezpośrednim sąsiedztwie występują litery. Poszukując informacji o niejakim Karolu, skądinąd opiekunie Karoliny, możemy spokojnie zlekceważyć całe przytoczone zdanie.

Ciąg znaków mysz, mimo że występuje słownikach, nie jest w naszym krótkim tekście słowem — słowo brzmi myszy. Tym niemniej, słowo to jest odmianą gramatyczną słowa „mysz”. Szukając informacji o myszach, powinniśmy wziąć je pod uwagę.

Ciąg znaków 13 powinien być interpretowany jako liczba, ale znak 1, będący jego częścią, wcale liczby nie oznacza — chociaż liczba jeden istnieje i bywa oznaczana właśnie cyfrą 1. Z kolei konstrukcje 13 myszy i 13 godzin podpadają pod pojęcie liczby mianowanej, czyli ilości; same słowa 13 i myszy rozpatrywane oddzielnie nie pozwalają na dostrzeżenie tego faktu, a rozróżnienie mian myszy i godzin również może być bardzo istotne.

W sytuacjach takich, jak omówione powyżej, wyszukiwanie nie może ograniczać się do poszukiwania interesującej frazy. Frazę tę należałoby uzupełnić opisem takich znaków lub fraz sąsiadujących, a także cech dodatkowych (np. że tworzy kompletne słowo), które sprawiają, że staje się dla nas interesująca. Czasami przeciwnie: warto okroić wyszukiwaną frazę np. do rdzenia słowa, które ma szansę pojawiać się w kilku formach gramatycznych.

Wyrażenia zgodne z danym wzorcem. Wyrażenia regularne

Oprócz wyrażeń „stałych”, których postać jest znana na początku i niezmienna w trakcie wyszukiwania bądź zamiany, możemy być zainteresowani wyszukiwaniem i zamianą bardziej skomplikowanych wyrażeń. Na przykład chcielibyśmy wyszukać w tekście informacje dotyczące kwot pieniężnych podanych w złotówkach (dla uproszczenia przyjmijmy, że interesujące nas kwoty podawane są w postaci liczb dziesiętnych z dokładnością do 1 grosza). Nasz wzorzec możemy przedstawić w postaci

ciąg-cyfr.cyfracyfra

gdzie ciąg-cyfr oznacza dowolny niezerowej długości ciąg znaków, w skład którego wchodzą wyłącznie znaki cyfr (być może za każdym razem inne). Wzorzec ten jest o wiele bardziej złożony, niż wzorce rozpatrywane poprzednio. Takie złożone wzorce możemy opisywać korzystając ze składni wyrażeń regularnych.

Do opisu wyrażeń regularnych stosuje się specjalną notację. Oto jej podstawowe reguły:

znaki liter i cyfr
oznaczają same siebie,
element*
oznacza powtórzenie poprzedniego elementu (zazwyczaj znaku) dowolną liczbę razy (być może zerową),
element+
oznacza powtórzenie poprzedniego elementu (zazwyczaj znaku) dowolną niezerową liczbę razy,
element?
oznacza powtórzenie poprzedniego elementu (zazwyczaj znaku) co najwyżej jeden raz,
element{n}
oznacza powtórzenie poprzedniego elementu (zazwyczaj znaku) dokładnie n razy,
.
oznacza dowolny pojedynczy znak,
[znakznak...znak]
oznacza pojedynczy znak z podanego zbioru znaków. Na przykład [0123456789] oznacza znak cyfry, a [abcdefghijklmnopqrstuvwxyz] pojedynczą małą literę łacińską,
[znak-znak]
oznacza pojedynczy znak z podanego zakresu znaków o kolejnych numerach. Na przykład [0-9] oznacza znak cyfry, a [a-z] pojedynczą małą literę łacińską,
[^znak-znak]
oznacza pojedynczy znak spoza podanego zbioru znaków. Na przykład [^0-9] oznacza dowolny znak nie będący cyfrą,
^
oznacza początek wiersza,
$
oznacza koniec wiersza,
\
oznacza zmianę kontekstu następnego znaku ze znaku sterującego na zwykły lub na odwrót. Jeżeli po znaku \ następuje znak sterujący, to oznacza, że należy go traktować jako zwykły znak, a nie rozkaz. Na przykład $ jest znakiem specjalnym oznaczającym koniec wiersza, ale już \$ oznacza zwykły znak dolara $. Jeżeli natomiast następny znak jest zwykłym znakiem, to znaczy że należy go traktować jako znak sterujący. Na przykład znak ( jest zwykłym znakiem nawiasu okrągłego, ale \( jest rozkazem sterującym stosowanym dla rozpoczęcia grupy znaków tworzących podwyrażenie. Ciąg \. reprezentuje zwykłą kropkę. Ciąg \\ reprezentuje zwykły znak odwrotnego ukośnika \ .

W niektórych sytuacjach wygodnie jest odwoływać się do znaków specjalnych za pomocą ich oznaczeń mnemonicznych. I tak

\t
oznacza znak tabulacji,
\n
oznacza znak końca wiersza.

Na przykład do wzorca [rR]ozdział[a-z]+ [0-9IVXLC]+ „pasuje” każde z wyrażeń:

Podczas wyszukiwania obowiązuje zasada dopasowania możliwie najdłuższego ciągu znaków. Znaczy to, że wyrażenia „pasujące” będące częścią początkową innego wyrażenia „pasującego” nie powinny być zgłaszane jako dopasowane. Do grupy tej należą wszystkie wyrażenia umieszczone w powyższym opisie w nawiasach obok wyrażeń dopasowanych.

Do rozpatrywanego wyżej wzorca [rR]ozdział[a-z]+ [0-9IVXLC]+ nie pasują:

Rozpatrywany wcześniej wzorzec „kwota w złotych” możemy zdefiniować następująco:

[0-9]+\.[0-9][0-9] zł

Wzorzec ten należałoby uzupełnić informacją kontekstową, że chodzi o kompletne słowa, żeby wykluczyć dopasowanie do zwrotów takich, jak o 13.45 złowiłem następnego okonia.

Zamiana wyrażeń stałych

Zamiana prosta polega na zastąpieniu wszystkich wystąpień pewnego ciągu znaków (napis1) innym ciągiem znaków (napis2):

napis1napis2

Czynność tę można zrealizować posługując się formularzem wyszukiwania i zamiany, dostępnym w interaktywnych edytorach plików znakowych.

Zamiana cykliczna polega na zamianie ról dwóch lub więcej ciągów znaków w tekście:

napis1napis2napis1

lub

napis1napis2napis3napis1

Postępowanie w myśl reguł prostej zamiany nie jest tu całkiem bezpieczne. Po wykonaniu zamian postaci

napis1napis2

stracimy informację na temat, który z napisów napis2 jest „stary”, a który powstał przed chwilą z tekstu napis1. Trzeba przyjąć bardziej złożony schemat postępowania, wykonując kolejno na całym tekście:

napis1napis-roboczy
napis2napis1
napis-roboczynapis2

gdzie napis-roboczy oznacza pewien ciąg znaków nie występujący w naszym pliku. Po wykonaniu zamian pierwszego typu nasz tekst nie zawiera w ogóle ciągu znaków napis1. Po następnym etapie (napis2napis1) nasz tekst nie zawiera ani jednego wystąpienia ciągu znaków napis2, gdyż w odpowiednich miejscach figuruje już napis1. Wreszcie na końcu wykonujemy zamiany napis-roboczynapis2. W przypadku dłuższego cyklu zamian postępujemy podobnie.

Zamiana fraz w zastosowaniach praktycznych

Wykorzystanie funkcji zamiany fraz do redakcji tekstu w formacie znakowym:

Wykorzystanie funkcji zamiany fraz do redagowania plików danych w formacie znakowym:

Zamiana separatorów lub znaków końca wiersza: wykorzystaj schowek do zapamiętania frazy przed umieszczeniem jej w formularzu dialogowym wyszukiwania i zamiany. W razie potrzeby (końce wiersza!) wykorzystaj składnię wyrażeń regularnych.

Przykłady wyszukiwania i zamiany wyrażeń regularnych

Realizacja wyszukiwania i zamiany wyrażeń regularnych wymaga użycia wyspecjalizowanych narzędzi. Dostarczają ich np. moduły wyszukiwania i zamiany (search and replace, match regular expressions) dostępne w interaktywnych edytorach plików znakowych, takich jak edytor programisty vp (Virtual Pascal) albo scite. Pierwszy ze wspomnianych edytorów dopuszcza jedynie wyszukiwanie wyrażeń regularnych i zastępowanie ich znanymi z góry ciągami znaków; fragmentów znalezionego wyrażenia nie można wykorzystać podczas zamiany. Istotność tego ograniczenia zilustrujemy w przykładach poniżej. Drugi z wymienionych edytorów jest od niego wolny.

Zastąp znaki końca wiersza średnikami

$ → ;

Wynikiem będzie dostawienie znaki średnika na końcu każdego wiersza pliku. Sam znak końca wiersza nie zostanie usunięty (chyba że użyte środowisko nietypowo interpretuje składnię wyrażeń regularnych). Do faktycznego złączenia wierszy tekstu trzeba użyć innych narzędzi.

Jedną z możliwości dają zaawansowane edytory, np. scite, wyposażone w opcję złącz paragraf. Polega ona na zastąpieniu końców wiersza spacjami w obrębie wyróżnionego bloku.

Inna możliwość wiąże się z wykorzystaniem filtra narzędziowego tr z systemu UNIX.

Zastąp średniki znakami końca wiersza

Symbol $ oznacza miejsce na końcu wiersza, a nie znak końca wiersza jako taki. Dlatego wzorzec zamiany

; → $

nie da oczekiwanego efektu (chyba że dane środowisko nietypowo interpretuje składnię wyrażeń regularnych). Należy raczej odwołać się do znaku końca wiersza za pomocą symbolu \n:

; → \n

Usuń wielokrotne spacje

" +" → " "

Cudzysłowy w powyższym przykładzie nie wchodzą w skład wzorców wyrażeń i w środowiskach komunikujących się z użytkownikiem za pośrednictwem formularzy nie należy ich wpisywać. W środowiskach odbierających argumenty z wiersza poleceń cudzysłowy są niezbędne (argumenty zawierają znaki spacji!).

Zastąp kropki dziesiętne przecinkami dziesiętnymi

cyfra.cyfradopasowana-cyfra,dopasowana-cyfra

Zastosowanie tej reguły zamiany nie powinno wyrządzić krzywdy skrótom wyrazów ani kropkom strzegącym końców zdań (gdyż nie pasują one do podanego wzorca).

[0-9]\.[0-9] → dopasowana-cyfra,dopasowana-cyfra

Oba edytory używane podczas tego ćwiczenia są w stanie znaleźć potrzebną frazę.

Znaki cyfr przed i po kropce trzeba pozostawić niezmienione tak, jak wystąpiły w tekście. Problem polega na tym, że dopasowane wyrażenie trzeba zastąpić innym, lecz niektóre jego części muszą pozostać niezmienione. Nie możemy po prostu opisać znaku dopasowana-cyfra jako [0-9], gdyż musi to być ten sam znak, który wystąpił w odpowiednim miejscu znalezionej frazy. Za każdym razem może on mieć inną wartość.

Tego zadania niektóre edytory (np. vp) nie potrafią wykonać. Jednak edytor scite doskonale sobie z nim poradzi.

Części wyrażenia, które powinny pozostać bez zmian podczas zamiany, trzeba ująć w nawiasy grupujące, a w polu „zamień na” użyć symbolicznych nazw dla zawartości tych nawiasów. Dla zawartości pierwszego nawiasu będziemy używać nazwy \1, dla zawartości drugiego — nazwy \2 itd.:

\([0-9]\)\.\([0-9]\) → \1,\2

W ostatnim rozdziale pierwszej części poznamy inne narzędzia, które są w stanie wykonać zaplanowaną wyżej czynność bez interaktywnej kontroli operatora.

Wartości dat zapisane w formacie yyyy-mm-dd zastąp odpowiednimi wartościami w formacie dd/mm/yy

Będziemy poszukiwać wzorca postaci

cztery cyfry-dwie cyfry-dwie cyfry

Każdy napis zgodny z tym wzorcem musimy zastąpić ciągiem znaków, który zawiera: numer dnia (czyli dwie ostatnie cyfry znalezionego tekstu), ukośnik jako separator, numer miesiąca (czyli dwie cyfry bloku środkowego), ukośnik jako separator, wreszcie dwie ostatnie z czterech cyfr początkowych jako numer roku. Zbudujemy najpierw wyrażenie regularne opisujące żądany wzorzec

[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]

a następnie wyróżnimy w nim parami nawiasów podwyrażenia, które należy zachować podczas zamiany:

[0-9][0-9]\([0-9][0-9]\)-\([0-9][0-9]\)-\([0-9][0-9]\)

Do pierwszego z nich począwszy od lewej strony wyrażenia (czyli do dwóch cyfr oznaczenia roku) będziemy się odwoływać nazwą \1, do drugiego (czyli do oznaczenia miesiąca) nazwą \2, zaś do trzeciego (oznaczenie numeru dnia) — nazwą \3. Musimy jeszcze opisać budowę wyrażenia zastępującego napotkany ciąg znaków:

[0-9][0-9]\([0-9][0-9]\)-\([0-9][0-9]\)-\([0-9][0-9]\) → \3/\2/\1

To już wszystko. Zauważmy na koniec, że zajmujemy się ciągami znaków, a nie wartościami liczbowymi. Tak więc np. data „pierwszy lutego 1993 roku” zapisana jako ciąg znaków 1993-2-1 nie jest zgodna z rozważanym przez nas wzorcem (dlaczego?), nie będzie więc przekształcona do pożądanej przez nas postaci 01/02/93. Natomiast ta sama data wyrażona ciągiem znaków 1993-02-01 jest z naszym wzorcem zgodna i zostanie już potraktowana tak, jak sobie tego życzymy.

Podstawy edycji nieinteraktywnej

Korzystanie z edytorów interaktywnych jest konieczne w przypadku tworzenia plików z danymi i bardzo wygodne przy wprowadzaniu stosunkowo nieskomplikowanych poprawek. Są jednak sytuacje, w których bezpośrednia edycja jest beznadziejnie pracochłonna. Z sytuacjami takimi możemy się spotkać np. w razie konieczności wprowadzenia identycznych niewielkich poprawek do kilkuset plików jednocześnie albo wydobycia niewielkich fragmentów tekstu z kilkuset plików i połączenia ich w jeden plik. Oczywiście można to wszystko wykonać „zwykłym” edytorem, ale czy warto?

Wiele prac związanych z przeformatowaniem danych składa się z ciągu elementarnych operacji edycyjnych, do których należą: wyszukiwanie fraz, zamiana fraz, wycinanie wierszy, wycinanie kolumn, łączenie poziome, łączenie pionowe, łączenie przez dopasowanie, porządkowanie ciągów danych.

Każdą z tych czynności można wykonać używając edytora ekranowego z jego funkcjami kopiowania, wycinania i wklejania bloków oraz automatycznego wyszukiwania i zamiany. Można je wykonać także za pomocą specjalistycznych programów narzędziowych. Programy te pracują nieinteraktywnie, tzn. musimy im precyzyjnie przekazać zakres pracy przed ich uruchomieniem, gdyż po uruchomieniu nie mamy możliwości sterowania ich przebiegiem. Dane wynikowe, będące efektem działania tych poleceń, są wysyłane do standardowego pliku wyjściowego, skąd można je przekierować np. do pliku albo na wejście innego programu.

Narzędzia do nieinteraktywnego przetwarzania pliów znakowych: cat/type, split, grep, head, tail, cut, paste, join, sed, tr oraz sort, są omówione w osobnym rozdziale.

Porównywanie zawartości plików

Tworząc dokument lub uzupełniając zbiory danych dla bezpieczeństwa tworzymy kopie zapasowe plików. Podczas pracy zespołowej możemy dostać poprawioną wersję pliku od współpracowników. Porównanie treści plików zawierających kolejne wersje dokumentu lub zestawu danych pozwala zlokalizować i przeanalizować różnice między nimi.

Porównywanie wizualne na wydruku lub monitorze jest męczące i niedokładne, gdyż z pewnością coś przeoczymy. Istnieją programy narzędziowe wspomagające automatyczne porównywanie plików.

Porównywanie znak po znaku pozwala stwierdzić, czy i w którym miejscu (w którym wierszu, na której pozycji) w plikach występują nie odpowiadające sobie znaki. Porównując dane w ten sposób możemy się dowiedzieć tylko, czy pliki zawierają identyczne ciągi znaków, czy nie, lecz nie sprawdzimy, na ile różnice te są dla nas istotne. Na przykład dodatkowa spacja w pliku zawierającym maszynopis co prawda wpływa na estetykę pracy, lecz na ogół nie zmienia treści przekazu:

-- Były sobie raz trzy siostrzyczki --↵rozpoczął Suseł...
                       | (pierwsza różnica)
-- Były sobie raz trzy  siostrzyczki --↵rozpoczął Suseł...

Taki sam dodatkowy znak w pliku danych może być bardzo istotny:

3c21454e5449545920546869735370656320224d6f64656c206f706973752064616e796368206879
                          | (pierwsza różnica)
3c21454e544954592054686973205370656320224d6f64656c206f706973752064616e796368206879

Co więcej, dodatkowy lub pominięty znak w jednym z plików powoduje natychmiast niezgodność następnych znaków, nawet jeżeli (tak jak w przypadku poniżej) są one po prostu przesunięte o jedną pozycję:

-- Były sobie raz trzy siostrzyczki --↵rozpoczął Suseł...
                       | ("s" ≠ " ")
		        | ("i" ≠ "s")
			 | ("o" ≠ "i")
			  ...
-- Były sobie raz trzy  siostrzyczki --↵rozpoczął Suseł...

Najwygodniej byłoby porównywać sens treści plików, ale z wielu powodów jest to bardzo trudne, o ile w ogóle możliwe.

Podstawowe narzędzia do porównywania plików znakowych dokonują synchronizacji treści, czyli próbują odnaleźć w obu plikach zestawy odpowiadających sobie wierszy, rozdzielonych fragmentami wstawionymi, usuniętymi lub zmienionymi.

-- Były sobie raz trzy siostrzyczki --↵ 
rozpoczął Suseł z wielkim pośpiechem --↵  
a na imię miały Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

← (identyczne) →
← (różne) →
← (różne) →
  (dodatkowy) →
↖ (identyczne) →

-- Były sobie raz trzy siostrzyczki --↵ 
rozpoczął suseł z wielkim pośpiechem --↵ 
 a na imię miały↵ 
 Elsie, Lacie i Tillie↵
i mieszkały na dnie studni...

Ponieważ synchronizację można przeprowadzić na wiele sposobów, każdy z programów narzędziowych może generować nieco inny raport.

Bardziej precyzyjne narzędzia dokonują także analizy wstawionych, zmienionych lub usuniętych fragmentów w odpowiadających sobie wierszach różniących się zawartością.

Programy narzędziowe do porównywania treści plików są na standardowym wyposażeniu systemów operacyjnych. W systemach UNIX są to programy diff (differences) i cmp (compare).

Sposób korzystania z tych programów jest opisany w instrukcjach użytkowania poleceń systemowych cmp i diff.

W systemach Windows do tego samego celu służy program fc (file compare). Wszystkie te programy porównują pliki, których nazwy podano jako parametry wywołania w wierszu poleceń, zaś raporty drukują na wyjściu standardowym, czyli zwykle w oknie terminala. Brak raportu oznacza zawsze, że pliki są identyczne.

-- Były sobie raz trzy siostrzyczki --↵rozpoczął Suseł...
                                                          | (brak różnic ⇒ brak raportu)
-- Były sobie raz trzy siostrzyczki --↵rozpoczął Suseł...

Program cmp dokonuje porównań znak po znaku. Programy diff i fc synchronizują pliki wierszami i drukują informacje o położeniu i zawartości wierszy nie dających się do siebie dopasować. Program fc ma ponadto opcję /b (binary) wymuszającą porównywanie znak po znaku.

Spróbujmy porównać pliki cplatin2.txt i cp1250.txt. Po wydaniu polecenia

diff cplatin2.txt cp1250.txt

dostaniemy na terminalu raport następującej treści:

6,7c6,7
< Do zapisu tej informacji wykorzystano zestaw znaków strony kodowej ISO-8859-2.
< Jeżeli program, którym posługujesz się przy odczycie, używa właśnie tego
---
> Do zapisu tej informacji wykorzystano zestaw znaków strony kodowej CP1250.
> Jeżeli program, którym posługujesz się przy odczycie, używa właœnie tego
10,12c10,12
< Strona kodowa ISO-8859-2 jest zgodna z Polską Normą zapisu
< i wymiany informacji. Jest wykorzystywana m. in. w polonizacji
< systemów UNIX.
---
> Strona kodowa CP1250 jest wykorzystywana m. in. w œrodowisku graficznym
> standardowo spolonizowanego systemu Windows.
> Spróbuj przeczytać ten tekst przy pomocy edytora o nazwie NOTEPAD.
14,22c14
< Do dobrego obyczaju należy, by dokumenty publikowane w
< Internecie zapisywać przy pomocy właśnie tego zestawu znaków.
< Odczytaj ten tekst dowolną przeglądarką internetową,
< wcześniej ustaw aktywną stronę kodową na "ISO-8859-2" lub "Latin-2" .
<
< Część graficzna systemu Windows używa innej strony kodowej.
< Odczytaj ten tekst programem NOTEPAD.
<
< Część tekstowa systemu Windows używa innej strony kodowej.
---
> Częœć tekstowa systemu Windows używa innej strony kodowej.
26c18
< niektóre edytory pozwalają na odczytanie numerów wyświetlanych znaków.
---
> niektóre edytory pozwalajš na odczytanie numerów wyœwietlanych znaków.
28d19
<

Program cmp dokona porównania znak po znaku. Efektem wykonania polecenia

cmp cplatin2.txt cp1250.txt

jest raport

cplatin2.txt cp1250.txt differ: char 252, line 6

Użycie programu fc, polegające na wydaniu polecenia

fc cplatin2.txt cp1250.txt

doprowadziło do uzyskania raportu

Comparing files CPLATIN2.TXT and CP1250.TXT
***** CPLATIN2.TXT

Do zapisu tej informacji wykorzystano zestaw znaków strony kodowej ISO-8859-2.
Jeżeli program, którym posługujesz się przy odczycie, używa właśnie tego
zestawu znaków, to nie masz kłopotów z czytaniem tego tekstu.
***** CP1250.TXT

Do zapisu tej informacji wykorzystano zestaw znaków strony kodowej CP1250.
Jeżeli program, którym posługujesz się przy odczycie, używa właœnie tego
zestawu znaków, to nie masz kłopotów z czytaniem tego tekstu.
*****

***** CPLATIN2.TXT

Strona kodowa ISO-8859-2 jest zgodna z Polską Normą zapisu
i wymiany informacji. Jest wykorzystywana m. in. w polonizacji
systemów UNIX.

Do dobrego obyczaju należy, by dokumenty publikowane w
Internecie zapisywać przy pomocy właśnie tego zestawu znaków.
Odczytaj ten tekst dowolną przeglądarką internetową,
wcześniej ustaw aktywną stronę kodową na "ISO-8859-2" lub "Latin-2" .

Część graficzna systemu Windows używa innej strony kodowej.
Odczytaj ten tekst programem NOTEPAD.

Część tekstowa systemu Windows używa innej strony kodowej.
Odczytaj ten tekst programem EDIT.
***** CP1250.TXT

Strona kodowa CP1250 jest wykorzystywana m. in. w œrodowisku graficznym
standardowo spolonizowanego systemu Windows.
Spróbuj przeczytać ten tekst przy pomocy edytora o nazwie NOTEPAD.

Częœć tekstowa systemu Windows używa innej strony kodowej.
Odczytaj ten tekst programem EDIT.
*****

***** CPLATIN2.TXT
Uwaga:
niektóre edytory pozwalają na odczytanie numerów wyświetlanych znaków.
Spróbuj!
***** CP1250.TXT
Uwaga:
niektóre edytory pozwalajš na odczytanie numerów wyœwietlanych znaków.
Spróbuj!
*****

***** CPLATIN2.TXT

***** CP1250.TXT
*****

Wreszcie program fc, zmuszony poleceniem

fc /b cplatin2.txt cp1250.txt

do porównania plików w trybie binarnym, stwierdził, co następuje (przytoczę tylko początek i koniec raportu):

Comparing files CPLATIN2.TXT and CP1250.TXT
000000FB: 49 43
000000FC: 53 50
000000FD: 4F 31
000000FE: 2D 32
000000FF: 38 35
00000100: 38 30
00000101: 35 2E
00000102: 39 0D
...............
00000302: 20 72
00000303: 6C F3
00000304: 75 62
00000305: 62 75
00000306: 20 6A
00000307: 22 21
00000308: 4C 0D
00000309: 61 0A
FC: CPLATIN2.TXT longer than CP1250.TXT

Czytelnik domyśli się pewnie, że raport zawiera (podane w układzie szesnastkowym) numery porządkowe pozycji, na których w każdym z plików znajduje się inny znak, oraz kody szesnastkowe tych znaków.

Raporty z porównań mogą służyć do wielu celów. Jednym z nich jest aktualizacja zawartości plików. Polega ona na zmodyfikowaniu zawartości jednego z porównywanych plików na podstawie raportu z porównania. Czynność tę da się zautomatyzować: raport z programu diff może służyć jako podstawa aktualizacji przeprowadzanej przez program patch. Przeprowadzanie aktualizacji jest sensowne zwłaszcza wtedy, kiedy zachodzi konieczność naniesienia drobnych poprawek do dużych plików.

Inne możliwe zastosowanie związane jest z prezentacją różnic w postaci wygodnej dla czytelnika. Służy do tego wiele programów narzędziowych, np. gtkdiff dla platform graficznych wyposażonych w bibliotekę GTK+ (w systemach MacOS, UNIX i Windows) lub merge i pmdiff firmy Araxis dla systemów Windows i OS/2. Także liczne zaawansowane edytory (np. vi) są wyposażone w moduły wizualnego porównywania zawartości plików.

Na ilustracji poniżej przedstawiono sesję programu gtkdiff, zainicjowaną poleceniem

gtkdiff cplatin2.txt cp1250.txt
sesja porównywania wizualnego plików znakowych

Programy do porównywania wizualnego mogą być samodzielnymi aplikacjami lub mieć charakter nakładek uprzyjemniających korzystanie z któregoś z omówionych wyżej narzędzi systemowych. Na przykład program gtkdiff wywołuje program diff, a otrzymany raport służy mu jako źródło informacji do odpowiedniego wyróżnienia fragmentów porównywanych tekstów. Uważna analiza raportu programu diff i zawartości okna programu gtkdiff powinna przekonać, że tak jest w istocie: oba programy podają te same informacje, chociaż w nieco inny sposób.

Więcej narzędzi do wizualnego porównywania plików przedstawia galeria ilustracji.

Pytania kontrolne

  1. Dlaczego czasami kursor „zjada” litery w tekście?
  2. Podaj przykłady wykorzystania zaawansowanych operacji edycyjnych przy przekształcaniu formatu lub zawartości zbioru danych.
  3. Na czym polega filtrowanie plików znakowych? jakie narzędzia do tego służą?
  4. Jak odnaleźć drobne różnice w zawartości dwóch plików znakowych?
  5. Jak połączyć ze sobą zawartość wielu plików tekstowych? Kiedy użycie techniki kopiuj–wklej staje się nieopłacalne?
© Copyright 2000–2009 by Jan Jełowicki, Katedra Matematyki Uniwersytetu Przyrodniczego we Wrocławiu
janj@aqua.up.wroc.pl
http://karnet.up.wroc.pl/~jasj