Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
lfa:2024:lab04 [2024/10/27 23:21] cata_chiru |
lfa:2024:lab04 [2024/10/29 09:27] (current) cata_chiru |
||
|---|---|---|---|
| Line 62: | Line 62: | ||
| crt_lst = list(set(lst)) | crt_lst = list(set(lst)) | ||
| return sorted(crt_lst, key = lambda x: (len(x), x)) | return sorted(crt_lst, key = lambda x: (len(x), x)) | ||
| + | |||
| # Global variable used to threshold the number of Star items | # Global variable used to threshold the number of Star items | ||
| INNER_STAR_NO_ITEMS = 3 | INNER_STAR_NO_ITEMS = 3 | ||
| + | |||
| class Regex: | class Regex: | ||
| '''Base class for Regex ADT''' | '''Base class for Regex ADT''' | ||
| + | |||
| def __str__(self) -> str: | def __str__(self) -> str: | ||
| '''Returns the string representation of the regular expression''' | '''Returns the string representation of the regular expression''' | ||
| pass | pass | ||
| + | |||
| def gen(self) -> [str]: | def gen(self) -> [str]: | ||
| '''Return a representative set of strings that the regular expression can generate''' | '''Return a representative set of strings that the regular expression can generate''' | ||
| pass | pass | ||
| + | |||
| + | def __len__(self) -> str: | ||
| + | '''Returns the length of the regular expression''' | ||
| + | pass | ||
| def eval_gen(self): | def eval_gen(self): | ||
| '''Prints the set of strings that the regular expression can generate''' | '''Prints the set of strings that the regular expression can generate''' | ||
| pass | pass | ||
| + | |||
| # TODO 0: Implementati Clasa Void dupa blueprint-ul de mai sus | # TODO 0: Implementati Clasa Void dupa blueprint-ul de mai sus | ||
| class Void(Regex): | class Void(Regex): | ||
| '''Represents the empty regular expression''' | '''Represents the empty regular expression''' | ||
| + | |||
| # Va returna Void ca string | # Va returna Void ca string | ||
| def __str__(self) -> str: | def __str__(self) -> str: | ||
| pass | pass | ||
| + | |||
| # Va genera un obiect din Python corespunzatoar clasei void | # Va genera un obiect din Python corespunzatoar clasei void | ||
| def gen(self) -> [str]: | def gen(self) -> [str]: | ||
| pass | pass | ||
| - | | + | |
| + | def __len__(self): | ||
| + | return 0 | ||
| def eval_gen(self): | def eval_gen(self): | ||
| print("Void generates nothing") | print("Void generates nothing") | ||
| - | + | ||
| + | |||
| # TODO 1: Implementati Clasa Epsilon-String (Empty) dupa blueprint-ul de mai sus | # TODO 1: Implementati Clasa Epsilon-String (Empty) dupa blueprint-ul de mai sus | ||
| class Empty(Regex): | class Empty(Regex): | ||
| '''Represents the empty string regular expression''' | '''Represents the empty string regular expression''' | ||
| + | |||
| # Va returna Empty ca string | # Va returna Empty ca string | ||
| def __str__(self) -> str: | def __str__(self) -> str: | ||
| pass | pass | ||
| + | |||
| # Va returna o lista corespunzatoare a ce stringuri produce sirul vid | # Va returna o lista corespunzatoare a ce stringuri produce sirul vid | ||
| def gen(self) -> [str]: | def gen(self) -> [str]: | ||
| pass | pass | ||
| - | | + | |
| + | # Va returna lungimea corespunzatoare sirului vid | ||
| + | def __len__(self) -> int: | ||
| + | pass | ||
| + | |||
| def eval_gen(self): | def eval_gen(self): | ||
| - | print("Empty string generates ''.") | + | print(f"Empty string has length {len(self)} generates ''.") |
| + | |||
| # TODO 2: Implementati functionalitatile necesare pentru Clasa Symbol dupa blueprint-ul de mai sus | # TODO 2: Implementati functionalitatile necesare pentru Clasa Symbol dupa blueprint-ul de mai sus | ||
| class Symbol(Regex): | class Symbol(Regex): | ||
| '''Represents a symbol in the regular expression''' | '''Represents a symbol in the regular expression''' | ||
| + | |||
| def __init__(self, char: str): | def __init__(self, char: str): | ||
| self.char = char | self.char = char | ||
| + | |||
| # TODO 2: Completati metodele __str__ si gen pentru clasa Symbol | # TODO 2: Completati metodele __str__ si gen pentru clasa Symbol | ||
| def __str__(self) -> str: | def __str__(self) -> str: | ||
| pass | pass | ||
| + | |||
| def gen(self) -> [str]: | def gen(self) -> [str]: | ||
| pass | pass | ||
| - | | + | |
| + | def __len__(self) -> int: | ||
| + | return 1 | ||
| def eval_gen(self): | def eval_gen(self): | ||
| self.gen() | self.gen() | ||
| + | |||
| # Dorim sa pastram in atributul words al clasei curente stringurile generate cu gen(self) | # Dorim sa pastram in atributul words al clasei curente stringurile generate cu gen(self) | ||
| - | return "Symbol {self.char} generates {self.words}" | + | return f"Symbol {self.char} has length {len(self)} generates {self.words}" |
| + | |||
| # TODO 3: Implementati functionalitatile necesare pentru Clasa Union dupa blueprint-ul de mai sus | # TODO 3: Implementati functionalitatile necesare pentru Clasa Union dupa blueprint-ul de mai sus | ||
| class Union(Regex): | class Union(Regex): | ||
| Line 137: | Line 151: | ||
| def __init__(self, *arg: [Regex]): | def __init__(self, *arg: [Regex]): | ||
| self.components = arg | self.components = arg | ||
| + | |||
| + | # TODO 3: Completati metodele __str__, gen, __len__ si eval_gen pentru clasa Union | ||
| - | # TODO 3: Completati metodele __str__, gen si eval_gen pentru clasa Union | + | # Hint: Look at the str.join method to create (expr1|expr2|...) |
| def __str__(self) -> str: | def __str__(self) -> str: | ||
| pass | pass | ||
| + | |||
| def gen(self) -> [str]: | def gen(self) -> [str]: | ||
| - | pass | + | pass |
| - | | + | |
| + | # We will consider the len of a Union as the max length of its components | ||
| + | def __len__(self) -> int: | ||
| + | pass | ||
| # Dupa modelul de la Symbol, vom dori ca urmatoarele eval sa implementeze | # Dupa modelul de la Symbol, vom dori ca urmatoarele eval sa implementeze | ||
| - | # return "Class {varianta toString() a clasei) generates {self.words}" | + | # return "Class {varianta toString() a clasei) has length {len(self)} and generates {self.words}" |
| def eval_gen(self) -> str: | def eval_gen(self) -> str: | ||
| - | pass | + | pass |
| + | |||
| # TODO 4: Implementati functionalitatile necesare pentru Clasa Concat dupa blueprint-ul de mai sus | # TODO 4: Implementati functionalitatile necesare pentru Clasa Concat dupa blueprint-ul de mai sus | ||
| class Concat(Regex): | class Concat(Regex): | ||
| '''Represents the concatenation of two regular expressions''' | '''Represents the concatenation of two regular expressions''' | ||
| + | |||
| def __init__(self, *arg : [Regex]): | def __init__(self, *arg : [Regex]): | ||
| self.components = arg | self.components = arg | ||
| - | + | ||
| - | # TODO 4: Completati metodele __str__, gen si eval_gen pentru clasa Concat | + | # TODO 4: Completati metodele __str__, gen, __len__ si eval_gen pentru clasa Concat |
| def __str__(self) -> str: | def __str__(self) -> str: | ||
| + | pass | ||
| + | |||
| + | def gen(self) -> [str]: | ||
| + | pass | ||
| + | |||
| + | def __len__(self) -> int: | ||
| pass | pass | ||
| - | def gen(self) -> [str]: | ||
| - | pass | ||
| - | |||
| def eval_gen(self) -> str: | def eval_gen(self) -> str: | ||
| - | pass | + | pass |
| + | |||
| # TODO 5: Implementati functionalitatile necesare pentru Clasa Star dupa blueprint-ul de mai sus | # TODO 5: Implementati functionalitatile necesare pentru Clasa Star dupa blueprint-ul de mai sus | ||
| class Star(Regex): | class Star(Regex): | ||
| Line 172: | Line 195: | ||
| def __init__(self, regex: Regex): | def __init__(self, regex: Regex): | ||
| self.regex = regex | self.regex = regex | ||
| + | |||
| + | # To memorize the base words generated by the regex inside the star, we store them in a list | ||
| self.base_words = [""] | self.base_words = [""] | ||
| - | self.base_gen() | ||
| self.words = [] | self.words = [] | ||
| + | |||
| + | # TODO 5: Completati metodele __str__, gen, __len__, eval_gen pentru clasa Star | ||
| + | def __str__(self) -> str: | ||
| + | pass | ||
| + | |||
| + | def gen(self, no_items = 10) -> [str]: | ||
| + | pass | ||
| - | + | # To ease your implementation we will consider a big number e.g. 1000000 as Infinity | |
| - | # TODO 5: Completati metodele __str__, gen, eval_gen pentru clasa Star | + | def __len__(self) -> int: |
| - | def __str__(self): | + | |
| pass | pass | ||
| - | + | ||
| - | def base_gen(self): | + | def eval_gen(self, no_items = 10): |
| - | '''To memorize the base words generated by the regex inside the star, we store them in a list''' | + | |
| - | if type(self.regex) == Star: | + | |
| - | # Implement Star.gen with a limiting threshold | + | |
| pass | pass | ||
| - | + | ||
| - | # Implement Regex.gen for the rest | + | |
| - | pass | + | |
| - | + | ||
| - | + | ||
| - | def gen(self, no_items = 10): | + | |
| - | pass | + | |
| - | + | ||
| - | def eval_gen(self, no_items = 10): | + | |
| - | pass | + | |
| - | + | ||
| if __name__ == "__main__": | if __name__ == "__main__": | ||
| - | |||
| - | # Example usage | ||
| - | |||
| r1 = Symbol('a') | r1 = Symbol('a') | ||
| r2 = Symbol('b') | r2 = Symbol('b') | ||
| regex_union = Union(r1, r2) | regex_union = Union(r1, r2) | ||
| regex_union.eval_gen() | regex_union.eval_gen() | ||
| + | |||
| e2 = Union(Symbol('a'),Symbol('b'), Symbol('c')) | e2 = Union(Symbol('a'),Symbol('b'), Symbol('c')) | ||
| e4 = Concat(r1, e2) | e4 = Concat(r1, e2) | ||
| e4.eval_gen() | e4.eval_gen() | ||
| - | | + | |
| e5 = Concat(e2, e2, r2) | e5 = Concat(e2, e2, r2) | ||
| e5.eval_gen() | e5.eval_gen() | ||
| + | |||
| star_ex = Star(r1) | star_ex = Star(r1) | ||
| star_ex.eval_gen() | star_ex.eval_gen() | ||
| + | |||
| regex_concat = Concat(regex_union, star_ex) | regex_concat = Concat(regex_union, star_ex) | ||
| regex_concat.eval_gen() | regex_concat.eval_gen() | ||
| + | |||
| last_expr = Concat(Star(Union(Symbol('a'), Symbol('b'))), Symbol('b'), Star(Symbol('c'))) | last_expr = Concat(Star(Union(Symbol('a'), Symbol('b'))), Symbol('b'), Star(Symbol('c'))) | ||
| last_expr.eval_gen() | last_expr.eval_gen() | ||
| - | </code> | + | </code> |
| | | ||
| The output should be similar to: | The output should be similar to: | ||
| <code> | <code> | ||
| - | Union (a | b) generates ['a', 'b']. | + | Union (a | b) has length 1 and generates ['a', 'b']. |
| - | Concat (a(a | b | c)) generates ['aa', 'ab', 'ac']. | + | Concat (a(a | b | c)) has length 2 and generates ['aa', 'ab', 'ac']. |
| - | Concat ((a | b | c)(a | b | c)b) generates ['aab', 'abb', 'acb', 'bab', 'bbb', 'bcb', 'cab', 'cbb', 'ccb']. | + | Concat ((a | b | c)(a | b | c)b) has length 3 and generates ['aab', 'abb', 'acb', 'bab', 'bbb', 'bcb', 'cab', 'cbb', 'ccb']. |
| - | Star (a*) generates ['', 'a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa', 'aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa', 'aaaaaaaaaa', '...']. | + | Star (a*) has length 10000000 generates ['', 'a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa', 'aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa', 'aaaaaaaaaa', '...']. |
| - | Concat ((a | b)(a*)) generates ['a', 'b', 'aa', 'ba', 'aaa', 'baa', 'aaaa', 'baaa']. | + | Concat ((a | b)(a*)) has length 10000001 and generates ['a', 'b', 'aa', 'ba', 'aaa', 'baa', 'aaaa', 'baaa', '...']. |
| - | Concat (((a | b)*)b(c*)) generates ['b', 'ab', 'bb', 'bc', 'aab', 'abb', 'abc', 'bab', 'bbb', 'bbc', 'bcc', 'aaab', 'aabb', 'aabc', 'abab', 'abbb', 'abbc', 'abcc', 'baab', 'babb', 'babc', 'bbab', 'bbbb', 'bbbc', 'bbcc', 'bccc', 'aaaab', 'aaabb', '...']. | + | Concat (((a | b)*)b(c*)) has length 20000001 and generates ['b', 'ab', 'bb', 'bc', 'aab', 'abb', 'abc', 'bab', 'bbb', 'bbc', 'bcc', 'aaab', 'aabb', 'aabc', 'abab', 'abbb', 'abbc', 'abcc', 'baab', 'babb', 'babc', 'bbab', 'bbbb', 'bbbc', 'bbcc', 'bccc', '...']. |
| </code> | </code> | ||
| Line 246: | Line 260: | ||
| For example, what is the outer class of a(a|b|c)? | For example, what is the outer class of a(a|b|c)? | ||
| - | <hidden> | + | <hidden Answer> |
| Concat | Concat | ||
| </hidden> | </hidden> | ||
| Line 252: | Line 266: | ||
| How can we write this Regex using our classes? | How can we write this Regex using our classes? | ||
| - | <hidden> | + | <hidden Answer> |
| Concat(Symbol('a'), Union(Symbol('a'), Symbol('b'), Symbol('c')) | Concat(Symbol('a'), Union(Symbol('a'), Symbol('b'), Symbol('c')) | ||
| </hidden> | </hidden> | ||
| Line 258: | Line 272: | ||
| <note> | <note> | ||
| - | |||
| Note that we have used the following code structures that takes a variable number of parameters as inputs for Concat and Union constructors: | Note that we have used the following code structures that takes a variable number of parameters as inputs for Concat and Union constructors: | ||
| Line 267: | Line 280: | ||
| This design choice was meant to ease your work when representing more complex regexes. The alternative would be to use binary operations and fuse the ones identical together: (a|b|c) = Concat(Symbol('a'), Concat(Symbol('b'), Symbol('c')) = (a|(b|c)) | This design choice was meant to ease your work when representing more complex regexes. The alternative would be to use binary operations and fuse the ones identical together: (a|b|c) = Concat(Symbol('a'), Concat(Symbol('b'), Symbol('c')) = (a|(b|c)) | ||
| - | |||
| </note> | </note> | ||
| What should it generate? | What should it generate? | ||
| - | <hidden> | + | <hidden Answer> |
| [aa, ab, ac] | [aa, ab, ac] | ||
| </hidden> | </hidden> | ||
| Line 278: | Line 290: | ||
| We should develop this process from simple examples to more complex ones: Symbol, Concat(Symbol, Symbol), Union(Symbol, Symbol), Concat(Symbol, Union), Concat(Union, Union)... | We should develop this process from simple examples to more complex ones: Symbol, Concat(Symbol, Symbol), Union(Symbol, Symbol), Concat(Symbol, Union), Concat(Union, Union)... | ||
| - | |||
| <note> | <note> | ||