diff --git a/lab2/img/ka.png b/lab2/img/ka.png index de717da..942e621 100644 Binary files a/lab2/img/ka.png and b/lab2/img/ka.png differ diff --git a/lab2/img/nka.png b/lab2/img/nka.png index e37ebe7..f03073a 100644 Binary files a/lab2/img/nka.png and b/lab2/img/nka.png differ diff --git a/lab2/img/result1.png b/lab2/img/result1.png index e4e9573..3cfa750 100644 Binary files a/lab2/img/result1.png and b/lab2/img/result1.png differ diff --git a/lab2/img/wrong.png b/lab2/img/wrong.png index 45c793d..6fc929c 100644 Binary files a/lab2/img/wrong.png and b/lab2/img/wrong.png differ diff --git a/lab2/programm/finite_automaton.py b/lab2/programm/finite_automaton.py index 46fce4c..a13ddb8 100644 --- a/lab2/programm/finite_automaton.py +++ b/lab2/programm/finite_automaton.py @@ -27,25 +27,28 @@ class FiniteAutomaton: for char in input_string: if char not in self.alphabet: - return f"Символ '{char}' не из алфавита", transitions_path + return f"Символ '{char}' не из алфавита ✗", transitions_path next_state = self._get_next_state(current_state, char) if next_state is None: - return "Строка не соответствует", transitions_path + return "Строка не соответствует ✗", transitions_path transitions_path.append(next_state) current_state = next_state return ( - "Строка соответствует" + "Строка соответствует ✓" if current_state in self.final_states - else "Строка не соответствует" + else "Строка не соответствует ✗" ), transitions_path - def generate_random_string(self, stop_probability: float = 0.3) -> str: + def generate_random_string( + self, stop_probability: float = 0.3 + ) -> tuple[str, list[str]]: result = [] current_state = self.initial_state + path = [current_state] while True: if ( @@ -59,5 +62,6 @@ class FiniteAutomaton: char = random.choice(transition) result.append(char) current_state = next_state + path.append(current_state) - return "".join(result) + return "".join(result), path diff --git a/lab2/programm/main.py b/lab2/programm/main.py index 143fd83..408b378 100644 --- a/lab2/programm/main.py +++ b/lab2/programm/main.py @@ -2,20 +2,22 @@ from finite_automaton import FiniteAutomaton def main(): - alphabet = set("+-0123456789.,eE") + alphabet = set("+-0123456789.eE") initial_state = "S0" - final_states = {"S2", "S4", "S7", "S8", "S9"} + final_states = {"S2", "S3", "S5", "S7", "S10"} transitions = { - "S0": [("+-", "S1"), ("123456789", "S2"), ("0", "S8")], - "S1": [("123456789", "S2"), ("0", "S8")], - "S2": [("0123456789", "S2"), (".,", "S3"), ("eE", "S5")], - "S3": [("0123456789", "S4")], - "S4": [("0123456789", "S4"), ("eE", "S5")], - "S5": [("+-", "S6"), ("123456789", "S7"), ("0", "S9")], - "S6": [("123456789", "S7"), ("0", "S9")], - "S7": [("0123456789", "S7")], - "S8": [(".,", "S3")], + "S0": [("+-", "S1"), ("123456789", "S2"), ("0", "S3"), (".", "S6")], + "S1": [("123456789", "S2"), ("0", "S3"), (".", "S6")], + "S2": [("0123456789", "S2"), (".", "S5"), ("eE", "S8")], + "S3": [("0", "S3"), ("123456789", "S4"), (".", "S5"), ("eE", "S8")], + "S4": [("0123456789", "S4"), (".", "S5"), ("eE", "S8")], + "S5": [("0123456789", "S5"), ("eE", "S8")], + "S6": [("0123456789", "S7")], + "S7": [("0123456789", "S7"), ("eE", "S8")], + "S8": [("+-", "S9"), ("0123456789", "S10")], + "S9": [("0123456789", "S10")], + "S10": [("0123456789", "S10")], } automaton = FiniteAutomaton( @@ -71,8 +73,9 @@ def main(): print(f"Ошибка: {e}") continue - random_string = automaton.generate_random_string(stop_prob) + random_string, path = automaton.generate_random_string(stop_prob) print(f"Сгенерированная строка: {random_string}") + print("Путь переходов:", " -> ".join(path)) else: print(f"Неизвестная команда: {cmd}") diff --git a/lab2/report.tex b/lab2/report.tex index fd2bb4e..b670ece 100644 --- a/lab2/report.tex +++ b/lab2/report.tex @@ -152,27 +152,27 @@ \textit{Вариант 15}. Соответствие вещественного числа разным форматам представления. - \newpage - \section {Математическое описание} - \subsection{Форматы представления вещественных чисел} - В данной лабораторной работе рассматриваются следующие форматы представления вещественных чисел. \begin{itemize} \item Целые числа, например: \texttt{''123''}, \texttt{''-456''}, \texttt{''0''}, в т. ч. \texttt{''+0''}, \texttt{''-0''}. - \item Десятичные числа с двумя возможными разделителями (точка или запятая), например: \texttt{''123.456''}, \texttt{''-456,789''}. - \item Экспоненциальная форма (буква E может быть как в верхнем, так и в нижнем регистре), например: \texttt{''1.23E4''}, \texttt{''-4,56e-7''}, \texttt{''7e8''}. + \item Десятичные числа с разделителем точка, например: \texttt{''123.456''}, \texttt{''-456.789''}, \texttt{''.5''}. + \item Экспоненциальная форма (буква E может быть как в верхнем, так и в нижнем регистре), например: \texttt{''1.23E4''}, \texttt{''-4.56e-7''}, \texttt{''7e8''}. \end{itemize} Формальное определение синтаксиса предложенного формата вещественных чисел в БНФ нотации: \begin{verbatim} - real ::= decimal | exponential - decimal ::= integer [separator digit {digit}] - integer ::= [sign] (nonzerodigit {digit} | "0") - exponential ::= decimal ("e" | "E") integer - sign ::= "+" | "-" - nonzerodigit ::= "1" | "2" | ... | "9" - digit ::= "0" | nonzerodigit - separator ::= "." | "," + real ::= [sign] (integer | float | exponentnumber) + sign ::= "+" | "-" + + integer ::= nonzerodigit {digit} | "0" {"0"} + nonzerodigit ::= "1" | "2" | ... | "9" + digit ::= "0" | nonzerodigit + + float ::= {digit} "." digitpart | digitpart "." + digitpart ::= digit {digit} + + exponentnumber ::= (digitpart | float) exponent + exponent ::= ("e" | "E") [sign] digitpart \end{verbatim} Где: \begin{itemize} @@ -182,7 +182,8 @@ \end{itemize} - + \newpage + \section {Математическое описание} \subsection{Языки и грамматики} Языком над конечным словарем $\Sigma$ называется произвольное множество конечных цепочек над этим словарем. @@ -248,22 +249,30 @@ Для разных форматов представления вещественных чисел были построены следующие регулярные выражения в соответствии с определённой БНФ нотацией: \begin{itemize} - \item Десятичные и целые числа: \\ - \texttt{[+-]?([1-9][0-9]*|0)([.,][0-9]+)?} + \item Целые числа: \\ + \texttt{[+-]?(0+|[1-9][0-9]*)} + \item Десятичные числа: \\ + \texttt{[+-]?([0-9]*\textbackslash.[0-9]+|[0-9]+\textbackslash.)} \item Экспоненциальная форма: \\ - \texttt{[+-]?([1-9][0-9]*|0)([.,][0-9]+)?[eE][+-]?([1-9][0-9]*|0)} + \texttt{[+-]?([0-9]+|[0-9]*\textbackslash.[0-9]+|[0-9]+\textbackslash.)[eE][+-]?[0-9]+} \end{itemize} - Объединяя все форматы в соответствии с нашей БНФ нотацией, получаем следующее регулярное выражение, которое распознает все форматы вещественных чисел: - - \texttt{[+-]?([1-9][0-9]*|0)([.,][0-9]+)?([eE][+-]?([1-9][0-9]*|0))?} - + Объединяя, получаем следующее регулярное выражение, которое распознает все форматы вещественных чисел в соответствии с БНФ нотацией: + \begin{verbatim} + [+-]?( + 0+| + [1-9][0-9]*| + [0-9]*\.[0-9]+| + [0-9]+\.| + ([0-9]+|[0-9]*\.[0-9]+|[0-9]+\.)[eE][+-]?[0-9]+ + ) + \end{verbatim} Разберём структуру этого выражения: \begin{itemize} \item \texttt{[+-]?} -- необязательный знак числа (плюс или минус) - \item \texttt{([1-9][0-9]*|0)} -- целая часть числа, которая может быть либо нулём, либо цифрой от 1 до 9, за которой следует произвольное количество цифр - \item \texttt{([.,][0-9]+)?} -- необязательная десятичная часть, состоящая из разделителя (точка или запятая) и как минимум одной цифры - \item \texttt{([eE][+-]?([1-9][0-9]*|0))?} -- необязательная экспоненциальная часть, состоящая из буквы E (в любом регистре), необязательного знака и целого числа + \item \texttt{0+|[1-9][0-9]*} -- целое число, которое может быть либо последовательностью нулей, либо цифрой от 1 до 9, за которой следует произвольное количество цифр. + \item \texttt{[0-9]*\textbackslash.[0-9]+|[0-9]+\textbackslash.} -- десятичное число, которое может быть представлено произвольным количеством цифр до и как минимум одной цифрой после точки, либо произвольным количеством цифр и одной точкой в конце. + \item \texttt{([0-9]+|[0-9]*\textbackslash.[0-9]+|[0-9]+\textbackslash.)[eE][+-]?[0-9]+} -- экспоненциальная форма числа, состоящая из произвольного количества цифр, либо десятичного числа, за которым следует буква E (в любом регистре), необязательный знак и как минимум одна цифра. \end{itemize} Таким образом, полученное регулярное выражение распознаёт формат представления вещественных чисел, рассматриваемый в данной работе, и полностью соответствует формальному определению, представленному в БНФ нотации. @@ -335,27 +344,29 @@ \footnotesize \begin{tabularx}{\textwidth}{|c|X|X|X|X|X|} \hline - \textbf{Состояние\textbackslash Вход} & \textbf{+-} & \textbf{0} & \textbf{1-9} & \textbf{.,} & \textbf{eE} \\ + \textbf{Состояние\textbackslash Вход} & \textbf{+-} & \textbf{0} & \textbf{1-9} & \textbf{.} & \textbf{eE} \\ \hline - $S_0$ & $S_1$ & $S_8$ & $S_2$ & -- & -- \\ + $S_0$ & $S_1$ & $S_3$ & $S_2$ & $S_6$ & -- \\ \hline - $S_1$ & -- & $S_8$ & $S_2$ & -- & -- \\ + $S_1$ & -- & $S_3$ & $S_2$ & $S_6$ & -- \\ \hline - $S_2$ & -- & $S_2$ & $S_2$ & $S_3$ & $S_5$ \\ + $S_2$ & -- & $S_2$ & $S_2$ & $S_5$ & $S_8$ \\ \hline - $S_3$ & -- & $S_4$ & $S_4$ & -- & -- \\ + $S_3$ & -- & $S_3$ & $S_4$ & $S_5$ & $S_8$ \\ \hline - $S_4$ & -- & $S_4$ & $S_4$ & -- & $S_5$ \\ + $S_4$ & -- & $S_4$ & $S_4$ & $S_5$ & $S_8$ \\ \hline - $S_5$ & $S_6$ & $S_9$ & $S_7$ & -- & -- \\ + $S_5$ & -- & $S_5$ & $S_5$ & -- & $S_8$ \\ \hline - $S_6$ & -- & $S_9$ & $S_7$ & -- & -- \\ + $S_6$ & -- & $S_7$ & $S_7$ & -- & -- \\ \hline - $S_7$ & -- & -- & $S_7$ & -- & -- \\ + $S_7$ & -- & $S_7$ & $S_7$ & -- & $S_8$ \\ \hline - $S_8$ & -- & -- & -- & $S_3$ & -- \\ + $S_8$ & $S_9$ & $S_{10}$ & $S_{10}$ & -- & -- \\ \hline - $S_9$ & -- & -- & -- & -- & -- \\ + $S_9$ & -- & $S_{10}$ & $S_{10}$ & -- & -- \\ + \hline + $S_{10}$ & -- & $S_{10}$ & $S_{10}$ & -- & -- \\ \hline \end{tabularx} \label{tab:nka} @@ -374,7 +385,6 @@ \label{fig:ka} \end{figure} - Матрица переходов для данного автомата представлена в Таблице~\ref{tab:ka}. \begin{table}[h!] \centering @@ -382,35 +392,39 @@ \footnotesize \begin{tabularx}{\textwidth}{|c|X|X|X|X|X|} \hline - \textbf{Состояние\textbackslash Вход} & \textbf{+-} & \textbf{0} & \textbf{1-9} & \textbf{.,} & \textbf{eE} \\ + \textbf{Состояние\textbackslash Вход} & \textbf{+-} & \textbf{0} & \textbf{1-9} & \textbf{.} & \textbf{eE} \\ \hline - $S_0$ & $S_1$ & $S_8$ & $S_2$ & $S_E$ & $S_E$ \\ + $S_0$ & $S_1$ & $S_3$ & $S_2$ & $S_6$ & $S_E$ \\ \hline - $S_1$ & $S_E$ & $S_8$ & $S_2$ & $S_E$ & $S_E$ \\ + $S_1$ & $S_E$ & $S_3$ & $S_2$ & $S_6$ & $S_E$ \\ \hline - $S_2$ & $S_E$ & $S_2$ & $S_2$ & $S_3$ & $S_5$ \\ + $S_2$ & $S_E$ & $S_2$ & $S_2$ & $S_5$ & $S_8$ \\ \hline - $S_3$ & $S_E$ & $S_4$ & $S_4$ & $S_E$ & $S_E$ \\ + $S_3$ & $S_E$ & $S_3$ & $S_4$ & $S_5$ & $S_8$ \\ \hline - $S_4$ & $S_E$ & $S_4$ & $S_4$ & $S_E$ & $S_5$ \\ + $S_4$ & $S_E$ & $S_4$ & $S_4$ & $S_5$ & $S_8$ \\ \hline - $S_5$ & $S_6$ & $S_9$ & $S_7$ & $S_E$ & $S_E$ \\ + $S_5$ & $S_E$ & $S_5$ & $S_5$ & $S_E$ & $S_8$ \\ \hline - $S_6$ & $S_E$ & $S_9$ & $S_7$ & $S_E$ & $S_E$ \\ + $S_6$ & $S_E$ & $S_7$ & $S_7$ & $S_E$ & $S_E$ \\ \hline - $S_7$ & $S_E$ & $S_E$ & $S_7$ & $S_E$ & $S_E$ \\ + $S_7$ & $S_E$ & $S_7$ & $S_7$ & $S_E$ & $S_8$ \\ \hline - $S_8$ & $S_E$ & $S_E$ & $S_E$ & $S_3$ & $S_E$ \\ + $S_8$ & $S_9$ & $S_{10}$ & $S_{10}$ & $S_E$ & $S_E$ \\ \hline - $S_9$ & $S_E$ & $S_E$ & $S_E$ & $S_E$ & $S_E$ \\ + $S_9$ & $S_E$ & $S_{10}$ & $S_{10}$ & $S_E$ & $S_E$ \\ + \hline + $S_{10}$ & $S_E$ & $S_{10}$ & $S_{10}$ & $S_E$ & $S_E$ \\ \hline \end{tabularx} \label{tab:ka} \end{table} + + + \newpage + Матрица переходов для данного автомата представлена в Таблице~\ref{tab:ka}. - \newpage - \phantom{text} \newpage \section{Особенности реализации} \subsection{Общая структура программы} @@ -502,9 +516,12 @@ def process_input(self, input_string: str) -> tuple[str, list[str]]: \end{enumerate} \begin{lstlisting}[caption={Код метода \texttt{generate\_random\_string}.}, label={lst:generate_random_string}] -def generate_random_string(self, stop_probability: float = 0.3) -> str: +def generate_random_string( + self, stop_probability: float = 0.3 +) -> tuple[str, list[str]]: result = [] current_state = self.initial_state + path = [current_state] while True: if ( @@ -518,8 +535,9 @@ def generate_random_string(self, stop_probability: float = 0.3) -> str: char = random.choice(transition) result.append(char) current_state = next_state + path.append(current_state) - return "".join(result) + return "".join(result), path \end{lstlisting} @@ -537,20 +555,22 @@ def generate_random_string(self, stop_probability: float = 0.3) -> str: \begin{lstlisting}[caption={Функция main.}, label={lst:Main}] def main(): - alphabet = set("+-0123456789.,eE") + alphabet = set("+-0123456789.eE") initial_state = "S0" - final_states = {"S2", "S4", "S7", "S8", "S9"} + final_states = {"S2", "S3", "S5", "S7", "S10"} transitions = { - "S0": [("+-", "S1"), ("123456789", "S2"), ("0", "S8")], - "S1": [("123456789", "S2"), ("0", "S8")], - "S2": [("0123456789", "S2"), (".,", "S3"), ("eE", "S5")], - "S3": [("0123456789", "S4")], - "S4": [("0123456789", "S4"), ("eE", "S5")], - "S5": [("+-", "S6"), ("123456789", "S7"), ("0", "S9")], - "S6": [("123456789", "S7"), ("0", "S9")], - "S7": [("0123456789", "S7")], - "S8": [(".,", "S3")], + "S0": [("+-", "S1"), ("123456789", "S2"), ("0", "S3"), (".", "S6")], + "S1": [("123456789", "S2"), ("0", "S3"), (".", "S6")], + "S2": [("0123456789", "S2"), (".", "S5"), ("eE", "S8")], + "S3": [("0", "S3"), ("123456789", "S4"), (".", "S5"), ("eE", "S8")], + "S4": [("0123456789", "S4"), (".", "S5"), ("eE", "S8")], + "S5": [("0123456789", "S5"), ("eE", "S8")], + "S6": [("0123456789", "S7")], + "S7": [("0123456789", "S7"), ("eE", "S8")], + "S8": [("+-", "S9"), ("0123456789", "S10")], + "S9": [("0123456789", "S10")], + "S10": [("0123456789", "S10")], } automaton = FiniteAutomaton( @@ -606,8 +626,9 @@ def main(): print(f"Ошибка: {e}") continue - random_string = automaton.generate_random_string(stop_prob) + random_string, path = automaton.generate_random_string(stop_prob) print(f"Сгенерированная строка: {random_string}") + print("Путь переходов:", " -> ".join(path)) else: print(f"Неизвестная команда: {cmd}") @@ -624,7 +645,7 @@ def main(): \label{fig:result1} \end{figure} - На Рис.~\ref{fig:wrong} представлена реакция программы на некорректный пользовательский ввод. + \newpage \begin{figure}[h!] \centering @@ -633,11 +654,14 @@ def main(): \label{fig:wrong} \end{figure} + На Рис.~\ref{fig:wrong} представлена реакция программы на некорректный пользовательский ввод. + \newpage \section*{Заключение} \addcontentsline{toc}{section}{Заключение} - В ходе выполнения лабораторной работы было построено регулярное выражение для распознавания различных форматов вещественных чисел, созданы недетерминированный и детерминированный конечные автоматы-распознаватели. На основе разработанного автомата была реализована программа, которая проверяет соответствие входной строки заданному формату и генерирует случайные корректные строки. + В ходе выполнения лабораторной работы было построено регулярное выражение для распознавания различных форматов вещественных чисел. В соответствии с теоремой Клини по заданному регулярному выражению, задающему регулярный + язык, был построен недетерминированный конечный автомат-распознаватель. Затем полученный конечный автомат был детерминирован. На основе разработанного автомата была реализована программа, которая проверяет соответствие входной строки заданному формату и генерирует случайные корректные строки. Из достоинств выполнения лабораторной работы можно выделить структурирование кода за счёт использования ООП. Вся логика работы с конечными автоматами вынесена в отдельный класс \texttt{FiniteAutomaton} с четко разделенными методами для проверки строк и генерации случайных строк. Создана удобная интерактивная консольная оболочка для взаимодействия с пользователем, позволяющая выполнять различные команды.