Академический Документы
Профессиональный Документы
Культура Документы
Москва 2022 г.
Содержание
Введение 3
1. Теоретические основы грамматики по регулярным выражениям 5
1.1. Сущность регулярных операций и выражений 5
1.2. Свойства регулярных языков 8
Заключение 22
Список литературы 23
Приложение 24
2
Введение
Регулярные выражения — это формальный язык для поиска и
обработки подстрок в тексте на основе метасимволов (подстановочных
знаков). Собственно, это строка-шаблон (англ. pattern, по-русски обычно
именуемый «шаблон», «маска»), состоящая из символов и метасимволов и
задающая правила поиска.
Регулярные выражения совершили прорыв в обработке текстов в конце
20-го века. Набор утилит, включенных в дистрибутивы UNIX, включая
редактор sed и фильтр grep, был одним из первых, кто популяризировал
регулярные выражения для обработки текстов. Многие современные языки
программирования имеют встроенную поддержку регулярных выражений.
Среди них ActionScript, Perl, Java, PHP, JavaScript, языки .NET Framework,
Python, Tcl, Ruby, Lua, Gambas, C++ (стандарт 2011 г.) и другие.
Некоторые текстовые редакторы и утилиты используют регулярные
выражения для поиска и замены текста. Например, с помощью регулярных
выражений вы можете указать шаблоны, позволяющие выполнять следующие
действия:
- Найти все последовательности символов "кошка" в любом контексте,
например: "кошка", "котлета", "терракота";
- найти одно слово «кошка» и заменить его на «кошка»;
- Найдите слово «персидский» или «чеширский» перед словом
«кошка»;
- Удалите из текста все предложения, в которых упоминается слово кот
или кошка.
Регулярные выражения также позволяют указывать более сложные
шаблоны поиска или замены.Целью курсовой работы является
рассмотрение процесса создания грамматики по регулярным выражениям и
построение дерева вывода.
3
Предметом курсовой работы является совокупность теоретических и
практических аспектов механизма создания грамматики по регулярным
выражениям.
Объектом курсовой работы являются регулярные выражения в языке
С#.
Задачами курсовой работы является:
- рассмотрение теоретических основ создания регулярных выражений;
- анализ синтаксиса регулярных выражений;
- практика создания грамматики по регулярным выражениям и
построения дерева вывода.
Структура курсовой работы. Курсовая работа состоит из введения,
двух глав, заключения и списка литературы.
4
1. Теоретические основы грамматики по регулярным выражениям
6
Два регулярных выражения α и β равны, α = β, если они обозначают
одно и то же множество.
Каждое регулярное выражение обозначает одно и только одно
регулярное множество, но для одного регулярного множества может
существовать сколь угодно много регулярных выражений, обозначающих это
множество.
При записи регулярных выражений будут использоваться круглые
скобки, как и для обычных арифметических выражений. При отсутствии
скобок операции выполняются слева на право с учетом приоритета.
Приоритет для операций принят следующий: первой выполняется итерация
(высший приоритет), затем конкатенация, потом - объединение множеств
(низший приоритет).
1. γ+αα* = γ+α*α = α*
2. α+β = β+α.
3. α+(β+γ) = (α+β)+γ
4. α(β+γ) = αβ+αγ
5. (β+γ)α = βα+γα
6. α(βγ) = (αβ)γ
7. α+α = α
8. α+α* = α*
7
9. λ+α* = α*+λ = a*
10. 0* = λ
11. 0α = α0 = 0
13. λα = αλ = α
14. (α*)* = α*
8
Например, обычные языки отключаются при следующих
действиях:-пересечения;
-объединения;
-дополнения;
-итерации;
-конкатенации;
-гомоморфизма (изменения имен символов и подстановки цепочек
вместо символов).
Поскольку регулярные множества замкнуты относительно операций
пересечения, объединения и дополнения, то они представляют булеву алгебру
множеств. Существуют и другие операции, относительно которых замкнуты
регулярные множества. Вообще говоря, таких операций достаточно много.
Регулярные языки представляют собой очень удобный тип языков. Для
них разрешимы многие проблемы, неразрешимые для других типов языков.
Например, доказано, что разрешимыми являются следующие
проблемы.
Проблема эквивалентности. Даны два регулярных языка L1(V) и L2(V).
Необходимо проверить, являются ли эти два языка эквивалентными.
Проблема принадлежности цепочки языку. Дан регулярный язык L(V) и
данному языку.
Проблема пустоты языка. Дан регулярный язык L(V). Необходимо
проверить, является ли этот язык пустым, то есть найти хотя бы одну цепочку
9
доказать разрешимость любой из этих проблем хотя бы для одного из
способов представления языка, тогда для остальных способов можно
воспользоваться алгоритмами преобразования, рассмотренными выше.
(Возможны и другие способы представления регулярных множеств, а для них
разрешимость указанных проблем будет уже не очевидна.)
Для регулярных грамматик также разрешима проблема однозначности -
доказано, что для любой регулярной грамматики можно построить
эквивалентную ей однозначную регулярную грамматику. Это очевидно,
поскольку для любой регулярной грамматики можно однозначно построить
регулярное выражение, определяющее заданный этой грамматикой язык.
Существует простой метод проверки, является или нет заданный язык
регулярным. Этот метод основан на проверке так называемой леммы о
разрастании языка. Доказано, что если для некоторого заданного языка
выполняется лемма о разрастании регулярного языка, то этот язык является
регулярным; если же лемма не выполняется, то и язык регулярным не
является.
Лемма о разрастании для регулярных языков формулируется
следующим образом: если дан регулярный язык и достаточно длинная
цепочка символов, принадлежащая этому языку, то в этой цепочке можно
найти непустую подцепочку, которую можно повторить сколь угодно много
раз, и все полученные таким способом новые цепочки будут принадлежать
тому же регулярному языку. (Если найденную подцепочку повторять
несколько раз, то исходная цепочка как бы «разрастается» - отсюда и
название «лемма о разрастании языков»).
константа р > 0, такая, что если α∈L и |α| ≥ р, то цепочку α можно записать в
виде α = δβε, где 0 < |β| < р, и тогда α' = δβiε, α'∈L ∀i ≥ 0.
10
Используя лемму о разрастании регулярных языков, докажем, что язык
L = {аnЬn | n > 0} не является регулярным.
Предположим, что этот язык регулярный, тогда для него должна
= аnЬn и запишем ее в виде α = δβε. Если β∈a+ или β∈b+ то тогда для i = 0
11
построить грамматику, эквивалентную заданному конечному автомату, а
потом уже найти регулярное выражение для заданного грамматикой языка.
Связь регулярных грамматик и конечных автоматов
На основе регулярной грамматики можно построить эквивалентный ей
конечный автомат и, наоборот, для заданного конечного автомата можно
построить эквивалентную ему регулярную грамматику.
Это очень важное утверждение, поскольку регулярные грамматики
используются для определения лексических конструкций языков
программирования. Создав автомат на основе известной грамматики, мы
получаем распознаватель для лексических конструкций данного языка. Таким
образом, удается решить задачу разбора для лексических конструкций языка,
заданных произвольной регулярной грамматикой. Обратное утверждение
также полезно, поскольку позволяет узнать грамматику, цепочки языка
которой допускает заданный автомат.
Для построения конечного автомата на основании известной
грамматики и для построения грамматики на основании данного конечного
автомата используются достаточно простые алгоритмы.
Все языки программирования определяют нотацию записи «слева
направо». В той же нотации работают и компиляторы. Поэтому далее
рассмотрены алгоритмы для леволинейных грамматик [4].
Q=VN∪{H}.
Если имеем δ(A,t) = {B1,B2,...,Bn}, n >0, где A∈Q, ∀n≥i≥0: Bi∈Q, t∈V,
= qo;
A ≠ qo.
15
2. Практика создания грамматики по регулярным выражениям и
построение дерева вывода
16
Таблица 2.1
Пример синтаксиса.
Пример Соответствие
a\.? a. или a
a\\\\b a\\b
a\[F\] a[F]
\Q+-*/\E +-*/
17
Таблица 2.2.
Замена некоторых символьных классов специальными метасимволами.
Символ Эквивалент Соответствие
\d [0-9] Цифровой символ.
\D [^0-9] Нецифровой символ.
\s [ \f\n\r\t\v] Пробельный символ.
\S [^ \f\n\r\t\v] Непробельный символ.
Буквенный или цифровой символ или знак
\w [[:word:]]
подчеркивания.
Любой символ, кроме буквенного или цифрового
\W [^[:word:]]
символа или знака подчеркивания.
Таблица 2.3.
Сиволы, позволяющие спозиционировать регулярное выражение
относительно элементов текста.
Представ Прим
Позиция Соответствие
ление ер
^ Начало строки ^a aaa aaa
$ Конец строки a$ aaa aaa
a\b aaa aaa
\b Граница слова
\ba aaa aaa
\B Не граница слова \Ba\B aaa aaa
Предыдущий aaa aaa (поиск остановился на 4-й
\G \Ga
успешный поиск позиции - там, где не нашлось a)
18
Р:S → С*) | К}
С → (* | Са | С{ | С} | С( | С* | С)
К →. { | Ка | К( | К* | К) | К{
Р':S → E) | К}
D →C*
С → D* I Са | C{ | C} | C( | C* | C)
E→(
К → { | Ка | K( | K* | K) | K{
грамматике.
C, D, K, H}.
Шаг 2. В качестве алфавита входных символов автомата берем
множество терминальных символов грамматики. Получаем: V = {"а", "(", "*",
")", "{", "}"}.
Шаг 3. Рассматриваем множество правил грамматики.
19
Для правил S → Е) | К} имеем δ(Е,")") = {S}; δ(K,"}") = {S}.
δ(С,"а") = {С}; δ(С,"{") = {С}; δ(С, "}") = {С}; δ(С,"(") = {С}; δ(С, “*”) =
= {К}; δ(К, “(") = {К}; δ(К,"*") = {К}; δ(К, ")") = {К}; δ(К, "{") = {К}.
δ(Н, "{") = {K}δ(H, "(") = {D} δ(К, "а") = {К} δ(К, "(") = {К}
δ(К, "*") = {К} δ(К, ")") = {К} δ(К, "{“) = {К} δ(К, ")") = {S}
δ(D, "*") = {С} δ(С, "а") = {С} δ(С, "{") = {С} δ(C, "}") = {С}
δ(С, "(") = {С} δ(С, "*") = {Е, С}δ(С, ")") = (С) δ(Е, “)”) = {S}
20
a, (,*,),{,}
Рис. 2.1.1. – Недетерминированный КА для языка комментариев в Borland
Pascal.
Это недетерминированный конечный автомат, поскольку существует
состояние, в котором множество, получаемое с помощью функции переходов
по одному и тому же символу, имеет более одного следующего состояния.
конечный автомат М'({S.E,С,D, К,Н}, {"а", "(", "*", ")", "{", "}"} .δ', H, {S}) с
функцией переходов:
δ'(Н, "{") = {К} δ'(Н, “(") = {D} δ'(К, "а") = {К} δ'(К, "(") = {К} δ'(К,
δ'(К, "{") = {К} δ'(К, "}") = {S) δ'(D, "*") = {С} δ'(С, "а") = {С} δ'(С,
δ'(С, "(") = {С} δ'(С, ")") = {С} δ'(С, "*") = {Е} δ'(Е, “а") = {С} δ'(E, “{“)
21
δ'(Е, "(") = {С} δ'(Е, "*") = {Е} δ'(Е, ")") = {S}
а, (,),{,}
Рис. 2.1.2. – Детерминированный КА для языка комментариев в Borland
Pascal.
22
2.4. Описание грамматики входного языка в форме Бэкуса-Наура
Грамматика для распознавания идентификаторов:
Грамматика для распознавания целых десятичных чисел со знаком:
Грамматика для лексического анализатора получается объединением
этих 2-х грамматик.
Множества крайних правых и крайних левых символов с указанием
шагов построения представлена в таблице 2.4.1:
Таблица 2.4.1
Множества крайних правых и крайних левых символов с указанием
шагов построения.
Символ Шаг 1 Последний шаг
(U) L(U) R(U) L(U) R(U)
S T T TEa TEa
T TE E TEa Ea
E a a a a
Таблица 2.4.2
Множества крайних правых и крайних левых терминальных символов
Символ Шаг 1 Шаг 2
(U) Lt(U) Rt(U) Lt(U) Rt(U)
S < > <= >= < > <= >= < > <= >= +-a < > <= >=+-a
T +- +- +-a +-a
E a a a a
Таблица 2.4.3
Матрица предшествования для грамматики
Символ < > + - * / <= >= a
⊥к
< = = =
> = = =
+ > > < >
23
- > > < >
* =
/ =
<= = = =
>= = = =
a = = >
< < <
⊥н
a<a;
24
Заключение
Так, в ходе рассмотрения курсовой работы мы пришли к выводу, что
регулярные выражения представляют удобный способ задания регулярных
множеств. Аналогично множествам, они определяются рекурсивно:
-регулярные базисные выражения задаются символами и определяют
соответствующие регулярные базисные множества, например, выражение f
задает одноэлементное множество {f} при условии, что f - символ алфавита
T;
-если p и q - регулярные выражения, то операции объединения,
конкатенации и итерации - p+q, pq, p*, q* - являются регулярными
выражениями, определяющими соответствующие регулярные множества.
По сути, регулярные выражения - это более простой и удобный способ
записи регулярных множеств в виде обычной строки. Каждое регулярное
множество, а, следовательно, и каждое регулярное выражение задает
некоторый язык L(T) в алфавите T.
Этот класс языков - достаточно мощный, с его помощью можно описать
интересные языки, но устроены они довольно просто - их можно определить
также с помощью простых грамматик, например, правосторонних грамматик.
Более важно, что для любого регулярного выражения можно построить
конечный автомат, который распознает, принадлежит ли заданное слово
языку, порожденному регулярным выражением. На этом основана
практическая ценность регулярных выражений.
С точки зрения практика регулярное выражение задает образец поиска.
После чего можно проверить, удовлетворяет ли заданная строка или ее
подстрока данному образцу. В языках программирования синтаксис
регулярного выражения существенно обогащается, что дает возможность
более просто задавать сложные образцы поиска.
Такие синтаксические надстройки, хотя и не меняют сути регулярных
выражений, крайне полезны для практиков, избавляя программиста от
ненужных сложностей.
25
26
Список литературы
27
Приложение
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
label
X,Y,Z,W,TX,AX;
var
a,i,j,k,count,c,n,g,b,bb,aa,ii:integer;
fin:file of char;
m:real;
fout:text;
ch,del,umn,minus,plus:char;
slovo:array[1..30] of string;
tip:array[1..20] of integer;
tip_:array[1..20] of string;
tmp,tmp_:string;
dl_tmp:integer;
s:string;
t:array[1..20] of string;
tt:array[1..20] of string;
e:array[1..20] of string;
a_:array[1..20] of string;
term:array[1..30] of char;
term_:array[1..30] of char;
nn:array[1..20] of integer;
begin
{ TODO -oUser -cConsole Main : Insert code here }
a:=0;writeln('‡ ¤ ЁҐ:');writeln;
writeln('Vipolnit leksicheskii analiz vxodnogo teksta,postroyit tablitsy
leksem');
writeln('I vipolnit sintaksicheskii razbor teksta po zadannoi grammatike s
postroeniem dereva ');
writeln('а §Ў®а .');
writeln('');
writeln('Zadannaya grammatika);writeln('');
writeln('S->T<T|T>T|T<=T|T>=T');
writeln('T->T+E|T-E|E');
writeln;
writeln('Vypolnili studenty VM-31 Petrov,Sorokin');
28
writeln('');
writeln('!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
writeln('Vhodnoi fail dolzhen nahoditsya na diske C:\spo3_in.txt');
writeln('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
writeln;readln;
assign(fin,'C:\spo3_in.txt');reset(fin);
for i:=1 to 30 do
slovo[i]:='';
j:=0;
i:=1;
c:=1;
a:=1;
ii:=1;
count:=0;
s:='';n:=0;
while not eof(fin) do
begin read(fin,ch);
s:=s+ch;n:=n+1;
Y: if(((ch>='a')and(ch<='z'))or((ch>='A')and(ch<='Z')))
then begin if(a=0)then i:=i+1;slovo[i]:=slovo[i]+ch;a:=1;tip[i]:=1;end
else if(ch='+')
then begin i:=i+1;slovo[i]:=slovo[i]+ch;a:=0;tip[i]:=3;end
else if(ch='-')
then begin i:=i+1;slovo[i]:=slovo[i]+ch;a:=0;tip[i]:=4;end
else if(ch='*')
then begin i:=i+1;slovo[i]:=slovo[i]+ch;a:=0;tip[i]:=5;end
else if(ch='/')
then begin i:=i+1;slovo[i]:=slovo[i]+ch;a:=0;tip[i]:=6;end
else if((ch='<')or(ch='>'))
then begin i:=i+1;slovo[i]:=slovo[i]+ch;a:=0;tip[i]:=7;end
else if(ch='=')
then begin slovo[i]:=slovo[i]+ch;a:=0;end
else if(ch='(')
then begin
i:=i+1;tip[i]:=2;
read(fin,ch);s:=s+ch;n:=n+1;a:=0;
slovo[i]:=slovo[i]+ch;
X:read(fin,ch);s:=s+ch;n:=n+1;
if((ch>='0')and(ch<='9'))
then begin slovo[i]:=slovo[i]+ch;goto X;end
else goto Y;
end
else if(ch=')')
then begin end
29
else begin j:=1;goto Z;end;
end;
close(fin);
for j:=1 to i do
begin
if(tip[j]=1)then tip_[j]:='identificator';
if(tip[j]=2)then tip_[j]:='celoe 10_noe chislo so znakom';
if(tip[j]=3)then tip_[j]:='znak slozheniya';
if(tip[j]=4)then tip_[j]:='znak vichitaniya';
if(tip[j]=5)then tip_[j]:='znak ymnozheniya';
if(tip[j]=6)then tip_[j]:='znak deleniya';
if(tip[j]=7)then tip_[j]:='znak neravenstva';
end;
c:=0;
assign(fout,'C:\spo3_out.txt');rewrite(fout);
writeln(fout,'');writeln(fout,'Tablica lecsem');
writeln(fout,'N Lecsema Tip lecsemi');
for j:=1 to i do
writeln(fout,j,' ',slovo[j],' ',tip_[j]);
writeln(fout,'');writeln(fout,'Derevo vivoda:');
tmp:='';
for j:=1 to 20 do
begin a_[j]:='';t[j]:='';tt[j]:='';e[j]:='';end;
aa:=1;
for j:=1 to n do
begin
if((s[j]='<')or(s[j]='>'))
then begin
for i:=1 to j-1 do
t:=t+s[i];
term:=s[j];
for i:=j+1 to n do
tt:=tt+s[i];
c:=1;
end
else if(s[j]='=')
then begin term:='=';delete(t,1,1);end;
end;
if(c=0)then begin j:=2;goto Z;end;
tmp:='T'+term+term+'T -> ';
write(fout,'S -> ',tmp);
b:=1;a:=1;bb:=0;aa:=3;
TX:
30
nn[b]:=length(t[b]);
if(nn[b]>0)then
begin
for i:=nn[b] downto 1 do
begin
if((t[b][i]='+')or(t[b][i]='-'))
then begin
if(t[b][i-1]<>'(')then
begin
for g:=i+1 to nn[b] do
e[a]:=e[a]+t[b][g];
term[aa]:=t[b][i];
for g:=1 to i-1 do
t[b+1]:=t[b+1]+t[b][g];
bb:=1;break;
end;end;
end;
if(bb=0)then begin e[a]:=t[b];delete(tmp,1,1);tmp:='E'+tmp;bb:=0;end
else begin delete(tmp,1,1);tmp:='T'+term[aa]+'E'+tmp;bb:=0;end;
a:=a+1;
end;
nn[b]:=length(tt[b]);
if(nn[b]>0)then
begin
for i:=nn[b] downto 1 do
begin
if((tt[b][i]='+')or(tt[b][i]='-'))
then begin
if(tt[b][i-1]<>'(')then
begin
for g:=i+1 to nn[b] do
e[a]:=e[a]+tt[b][g];
aa:=aa+1;
term[aa]:=tt[b][i];
for g:=1 to i-1 do
tt[b+1]:=tt[b+1]+tt[b][g];
bb:=1;break;
end;end;
end;
dl_tmp:=length(tmp);
for g:=dl_tmp downto 1 do
if(tmp[g]='T')then
begin k:=g;break;end;
delete(tmp,k,1);
31
if(bb=0)then begin insert('E',tmp,k);e[a]:=tt[b];write(fout,tmp);bb:=0;end
else begin
tmp_:='T'+term[aa]+'E';insert(tmp_,tmp,k);write(fout,tmp);bb:=0;end;
a:=a+1;
end;
begin
for g:=1 to length(e[ii]) do
begin
if((e[ii][g]='*')or(e[ii][g]='/'))
then begin
for i:=1 to g-1 do
a_:=a_+e[ii][i];
term_:=e[ii][g];
for i:=g+1 to length(e[ii]) do
a_:=a_+e[ii][i];
bb:=1;break;
end;
end;
for g:=1 to length(tmp) do
if(tmp[g]='E') then
begin delete(tmp,g,1);break;end;
if(bb=0)then begin
insert('a',tmp,g);bb:=0;
end
else begin
tmp_:='a'+term_+'a';
insert(tmp_,tmp,g);bb:=0;
end;
ii:=ii+1;
for g:=1 to length(e[ii]) do
begin
if((e[ii][g]='*')or(e[ii][g]='/'))
then begin
for i:=1 to g-1 do
a_:=a_+e[ii][i];
term_:=e[ii][g];
for i:=g+1 to length(e[ii]) do
a_:=a_+e[ii][i];
bb:=1;break;
end;
end;
for g:=1 to length(tmp) do
if(tmp[g]='E') then
32
begin delete(tmp,g,1);break;end;
if(bb=0)then begin
insert('a',tmp,g);bb:=0;
end
else begin
tmp_:='a'+term_+'a';
insert(tmp_,tmp,g);bb:=0;
end;
c:=0;ii:=ii+1;
end;
if((length(t[b])>0)or(length(tt[b])>0))
then
begin b:=b+1;goto TX;end;
for g:=length(tmp) downto 1 do
begin
if(tmp[g]='>')then begin delete(tmp,g-1,10);break;end;
end;
write(fout,tmp,'-> ',s);
close(fout);
Z:if(j=1)
then writeln('Leksicheskaya oshibka!');
if(j=2)
then readln;
end.
end.
33