Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

Autor artykułu: mgr Jerzy Wałaszek

©2025 mgr Jerzy Wałaszek
I LO w Tarnowie

Naiwne wyszukiwanie wzorca w tekście

SPIS TREŚCI
Tematy pomocnicze
Podrozdziały

Problem

W łańcuchu znakowym s należy znaleźć wszystkie wystąpienia wzorca p.

Rozwiązanie nr 1

Problem Wyszukiwania Wzorca –  WW (ang. pattern matching) to jeden z podstawowych problemów tekstowych, który intensywnie badali wybitni informatycy. Rozwiązaniem jest wskazanie w ciągu s wszystkich pozycji i takich, że zachodzi równość:

s[i:i+|p|] = p

Oznacza to, iż wzorzec p jest fragmentem łańcucha s występującym na pozycji i-tej.

Algorytm N – naiwny – ustawia okno o długości wzorca p na pierwszej pozycji w łańcuchu s. Następnie sprawdza, czy zawartość tego okna jest równa wzorcowi p. Jeśli tak, pozycja okna jest zwracana jako wynik, po czym okno przesuwa się o jedną pozycję w prawo i cała procedura powtarza się. Algorytm kończymy, gdy okno wyjdzie poza koniec łańcucha. Klasa pesymistycznej złożoności obliczeniowej algorytmu N jest równa O(n×m), gdzie n oznacza liczbę znaków tekstu, a m liczbę znaków wzorca. Jednakże w typowych warunkach algorytm pracuje w czasie O(n), ponieważ zwykle wystarczy porównanie kilku początkowych znaków okna z wzorcem, aby stwierdzić, iż są one niezgodne.

Algorytm naiwny wyszukiwania wzorca w łańcuchu tekstowym

Wejście:

s : łańcuch znakowy
p : łańcuch wzorca

Wyjście:

Wszystkie pozycje wzorca p w łańcuchu s.

Elementy pomocnicze:

i : pozycja okna, i ∈ N.
n : długość łańcucha s; n ∈ N.
m : długość wzorca p; m ∈ N.

Lista kroków:

K01: n ← |s| ; obliczamy długość łańcucha s
K02: m ← |p| ; obliczamy długość wzorca p
K03: Dla i = 0, 1, …n-m:
     wykonuj krok K04
K04:   Jeśli p = s[i:i+m], ; okno zawiera wzorzec?
       to pisz i ; jeśli tak, to wypisujemy pozycję
K05: Zakończ

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Program generuje 60 znakowy łańcuch zbudowany z pseudolosowych kombinacji liter A, BC. Następnie losuje 3 literowy wzorzec z tych samych liter i algorytmem naiwnym wyszukuje wszystkie wystąpienia wzorca w łańcuchu. Pozycję wzorca zaznacza znakiem ^.
Pascal
// Algorytm WWN
// Data:   29.05.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

program prg;

var
  s, p : ansistring;
  i : integer;

begin
  randomize;

  // generujemy łańcuch
  s := '';
  for i := 1 to 60 do
    s := s+chr(65+random(3));

  // generujemy wzorzec
  p := '';
  for i := 1 to 3 do
    p := p+chr(65+random(3));

  // wypisujemy wzorzec
  writeln(p);

  // wypisujemy łańcuch
  writeln(s);

  // szukamy wzorca w łańcuchu
  for i := 1 to 58 do
    if p = copy(s, i, 3) then
      write('^')
    else
      write(' ');
  writeln;
  writeln;
end.
C++
// Algorytm WWN
// Data:   29.05.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
  string s, p;
  int i;
 
  srand(time(NULL));

  // generujemy łańcuch
  s = "";
  for(i = 0; i < 60; i++)
    s += char(65+(rand() % 3));

  // generujemy wzorzec
  p = "";
  for(i = 0; i < 3; i++)
    p += char(65+(rand() % 3));

  // wypisujemy wzorzec
  cout << p << endl;

  // wypisujemy łańcuch
  cout << s << endl;

  // szukamy wzorca w łańcuchu
  for(i = 0; i < 58; i++)
    cout << (p == s.substr(i, 3) ? "^": " ");
  cout << endl << endl;
  return 0;
}
Basic
' Algorytm WWN
' Data:   29.05.2008
' (C)2020 mgr Jerzy Wałaszek
'---------------------------

Dim As String s, p
Dim As Integer i

Randomize

' generujemy łańcuch
s = ""
For i = 1 To 60
  s += Chr(65+Cint(Rnd*2))
Next

' generujemy wzorzec
p = ""
For i = 1 To 3
  p += Chr(65+Cint(Rnd*2))
Next

' wypisujemy wzorzec
Print p

' wypisujemy łańcuch
Print s

' szukamy wzorca w łańcuchu
For i = 1 To 58
  If p = Mid(s, i, 3) Then
    Print "^";
  Else
    Print " ";
  End If
Next
Print: Print
End
Python (dodatek)
# Algorytm WWN
# Data:   6.03.2024
# (C)2024 mgr Jerzy Wałaszek
#---------------------------

import random

s = "" # łańcuch
p = "" # wzorzec

# generujemy łańcuch
for i in range(60):
    s += chr(random.randrange(65, 68))
# generujemy wzorzec
for i in range(3):
    p += chr(random.randrange(65, 68))
# wypisujemy wzorzec
print(p)
# wypisujemy łańcuch
print(s)
# szukamy wzorca w łańcuchu
for i in range(58):
    if p == s[i:i+3]:
        print("^", end="")
    else:
        print(" ", end="")
print()
print()
Wynik:
ACC
CAACCAABCBCAAAABAACCABBBAACCCCACBCACBBABAAABCCABAABCBAABCACC
  ^              ^       ^                               ^

Wyszukiwanie wzorca algorytmem N
(C)2020 mgr Jerzy Wałaszek


do podrozdziału  do strony 

Rozwiązanie nr 2

Algorytm N możemy nieco usprawnić wykorzystując ideę wartowników. Na końcu łańcucha oraz wzorca umieszczamy dwa różne znaki. Zapobiegną one wyjściu poza obszar łańcucha przy testowaniu znaków w oknie i we wzorcu. Dzięki nim odpadnie sprawdzanie zakresu indeksów w oknie – w efekcie algorytm wykona mniej operacji.

Algorytm naiwny wyszukiwania wzorca z wartownikami

Wejście:

s : łańcuch znakowy.
p : łańcuch wzorca.

Wyjście:

Wszystkie pozycje wzorca p w łańcuchu s.

Elementy pomocnicze:

i : pozycja okna w łańcuchu s; i ∈ N.
j : pozycja wewnątrz okna; j ∈ N.
n : długość łańcucha s; n ∈ N.
m : długość wzorca p; m ∈ N.

Lista kroków:

K01: n ← |s| ; obliczamy długość łańcucha s
K02: m ← |p| ; obliczamy długość wzorca p
K03: ss+'X' ; na końcu łańcucha umieszczamy wartownika
K04: pp+'Y' ; na końcu wzorca umieszczamy innego wartownika
K05: Dla i = 0, 1, …, n-m: ; pozycje okna
     wykonuj kroki K06…K08
K06:  j ← 0 ; pozycja w oknie i we wzorcu
K07:  Dopóki s[i+j] = p[j], ; szukamy pierwszego różnego
      wykonuj jj+1     ; znaku okna i wzorca
K08:  Jeśli j = m, ; sprawdzamy, czy cały wzorzec
      to pisz i    ; wystąpił w oknie
K09: Usuń ostatni znak z s ; pozbywamy się wartownika z łańcucha
K10: Usuń ostatni znak z p ; pozbywamy się wartownika ze wzorca
K11: Zakończ

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Program generuje 60 znakowy łańcuch zbudowany z pseudolosowych kombinacji liter A, BC. Następnie losuje 3 literowy wzorzec z tych samych liter i algorytmem naiwnym wyszukuje wszystkie wystąpienia wzorca w łańcuchu. Pozycję wzorca zaznacza znakiem ^.
Pascal
// Algorytm WWN z wartownikami
// Data:   30.05.2008
// (C)2020 mgr Jerzy Wałaszek
//-----------------------------

program prg;

var
  s, p : ansistring;
  i, j : integer;

begin
  randomize;

  // generujemy łańcuch
  s := '';
  for i := 1 to 60 do
    s := s+chr(65+random(3));

  // generujemy wzorzec
  p := '';
  for i := 1 to 3 do
    p := p+chr(65+ random(3));

  // wypisujemy wzorzec
  writeln(p);

  // wypisujemy łańcuch
  writeln(s);

  // dodajemy wartowników
  s := s+'X'; p := p+'Y';

  // szukamy wzorca w łańcuchu
  for i := 1 to 58 do
  begin
    j := 0;
    while s[i+j] = p[j+1] do inc(j);
    if j = 3 then
      write('^')
    else
      write(' ');
  end;
  writeln;
  writeln;
end.
C++
// Algorytm WWN z wartownikami
// Data:   30.05.2008
// (C)2020 mgr Jerzy Wałaszek
//----------------------------

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
  string s, p;
  int i, j;

  srand(time(NULL));

  // generujemy łańcuch

  s = "";
  for(i = 0; i < 60; i++)
    s += char(65+(rand() % 3));

  // generujemy wzorzec
  p = "";
  for(i = 0; i < 3; i++)
    p += char(65+(rand() % 3));

  // wypisujemy wzorzec
  cout << p << endl;

  // wypisujemy łańcuch
  cout << s << endl;

  // dodajemy wartowników
  s += "X"; p += "Y";

  // szukamy wzorca w łańcuchu
  for(i = 0; i < 58; i++)
  {
    for(j = 0; s[i+j] == p[j]; j++);
    cout << (j == 3 ? "^" : " ");
  }
  cout << endl << endl;
  return 0;
}
Basic
' Algorytm WWN z wartownikami
' Data:   30.05.2008
' (C)2020 mgr Jerzy Wałaszek
'-----------------------------

Dim As String s, p
Dim As Integer i, j

Randomize

' generujemy łańcuch
s = ""
For i = 1 To 60
  s += Chr(65+Cint(Rnd*2))
Next

' generujemy wzorzec
p = ""
For i = 1 To 3
  p += Chr(65+Cint(Rnd*2))
Next

' wypisujemy wzorzec
Print p

' wypisujemy łańcuch
Print s

' dodajemy wartowników
s += "X": p += "Y"

' szukamy wzorca w łańcuchu
For i = 1 To 58
  j = 0
  While Mid(s, i+j, 1) = Mid(p, j+1, 1)
    j += 1
  Wend
  If j = 3 Then
    Print "^";
  Else
    Print " ";
  End If
Next
Print: Print
End
Python (dodatek)
# Algorytm WWN z wartownikami
# Data:   6.03.2024
# (C)2024 mgr Jerzy Wałaszek
#---------------------------

import random

# generujemy łańcuch
s = ""
for i in range(60):
    s += chr(random.randrange(65, 68))
# generujemy wzorzec
p = ""
for i in range(3):
    p += chr(random.randrange(65, 68))
# wypisujemy wzorzec
print(p)
# wypisujemy łańcuch
print(s)
# dodajemy wartowników
s += "X"
p += "Y"
# szukamy wzorca w łańcuchu
for i in range(58):
    j = 0
    while s[i+j:i+j+1] == p[j:j+1]:
        j += 1
    if j == 3:
        print("^", end="")
    else:
        print(" ", end="")
print()
print()

Jako ćwiczenie dodaj do programu usuwanie wartowników przed zakończeniem jego pracy.


do podrozdziału  do strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2025 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.