feat: MVP проекта закончено
This commit is contained in:
@ -4,13 +4,68 @@ this class applies markov algorightm to given string
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from collections import OrderedDict
|
||||
from typing import ClassVar
|
||||
from rule import Rule, EMPTY_SYMBOL
|
||||
|
||||
@dataclass
|
||||
class Rulebook:
|
||||
rules: OrderedDict[str, str]
|
||||
MAX_DEPTH: ClassVar[int] = 100
|
||||
rules: list[Rule]
|
||||
|
||||
def transform(self, string: str) -> str:
|
||||
"""
|
||||
Applies the next appropriate rule to given string. The
|
||||
priority of rules is determined by their indexes in list
|
||||
of rules. Lesser the index - higher the priority.
|
||||
|
||||
Return transformed string
|
||||
"""
|
||||
|
||||
for _ in range(self.MAX_DEPTH):
|
||||
rule = self.find_appropriate_rule(string)
|
||||
if rule is None:
|
||||
return string
|
||||
string = self._apply_rule(rule, string)
|
||||
if rule.is_blocking:
|
||||
return string
|
||||
raise ValueError("The amount of transformations exceeded "
|
||||
f"{self.MAX_DEPTH}. You can change maximum "
|
||||
"amount by setting class variable MAX_DEPTH,"
|
||||
" but may be something wrong with your input")
|
||||
|
||||
|
||||
def find_appropriate_rule(self, string) -> Rule | None:
|
||||
"""
|
||||
Searches for appropriate rule in rules list and if
|
||||
found one returns it, otherwise returns None
|
||||
"""
|
||||
for rule in self.rules:
|
||||
if self._is_rule_appropriate(rule, string):
|
||||
return rule
|
||||
|
||||
def _apply_rule(self, rule: Rule, string: str) -> str:
|
||||
"""
|
||||
Tries to apply given rule to string. Doesn't check
|
||||
wether the rule is appropriate or not. Inapplicability
|
||||
leads to undefined behaviour
|
||||
"""
|
||||
if rule.operand == EMPTY_SYMBOL:
|
||||
string = EMPTY_SYMBOL + string
|
||||
|
||||
string = (
|
||||
string
|
||||
.replace(rule.operand, rule.target, 1)
|
||||
.replace(EMPTY_SYMBOL, '')
|
||||
)
|
||||
return string
|
||||
|
||||
def _is_rule_appropriate(self, rule: Rule, string: str) -> bool:
|
||||
"""
|
||||
Concrete realization of rule applicability check. Moved to separate
|
||||
function mostly for extensibility purposes
|
||||
"""
|
||||
# Hardest part is always about empty set
|
||||
if rule.operand == EMPTY_SYMBOL:
|
||||
return True
|
||||
return rule.operand in string
|
||||
|
||||
def __call__(self, string: str):
|
||||
"""aplies rule to the given string"""
|
||||
raise NotImplementedError("Sorry, we still don't know how to apply"
|
||||
"algorithm to your string")
|
||||
|
||||
@ -38,12 +38,31 @@ class RulesParser:
|
||||
raise ValueError(f"Can't recognize transform symbol. "
|
||||
f"\"{self.TRANSFORM}\" or \"{self.B_TRANSFORM}\""
|
||||
f" expected, but \"{arrow}\" encountered")
|
||||
|
||||
#optimising empty symbol
|
||||
return Rule(
|
||||
operand=tokens[0],
|
||||
target=tokens[2],
|
||||
operand=self._optimise_empty(tokens[0]),
|
||||
target=self._optimise_empty(tokens[2]),
|
||||
is_blocking=is_blocking
|
||||
)
|
||||
|
||||
def _optimise_empty(self, string: str) -> str:
|
||||
"""
|
||||
Empty symbol has meaning only while it's the only
|
||||
symbol in the string (I hope i'm not wrong right now),
|
||||
so all empty symbols can be optimised
|
||||
|
||||
Returns sting without EMPTY symbols if deleting them
|
||||
is semantically possible, returns unchanges string if
|
||||
nothing can be optimised
|
||||
|
||||
NOTE: right now contains naive implementation
|
||||
"""
|
||||
string = re.sub(self.EMPTY+'+', EMPTY_SYMBOL, string)
|
||||
if re.fullmatch(self.EMPTY, string):
|
||||
return string
|
||||
return re.sub(self.EMPTY, '', string)
|
||||
|
||||
def _get_lines(self, src: str) -> list[str]:
|
||||
"""
|
||||
Get cleaned lines only with rules to parse
|
||||
@ -65,5 +84,4 @@ class RulesParser:
|
||||
Strips whitespaces at the end of lines
|
||||
"""
|
||||
result = re.sub(r' +$', '', src, flags=re.M)
|
||||
# result = re.sub(r"\n+", r'\n', result)
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user