티스토리 뷰
[조건]
- 계산기에 들어갈 수식을 생성한다.
인자값
ops : 연산자의 갯수
max: 숫자의 최대값
bk: 연산자 하나당 괄호의 생성 확률
types: 사용할 연산자 타입들
리턴값
수식 문자열
예시
create(ops=10, max=10000, bk=30, types="+-*/")
연산자의 갯수는 10개
숫자는 모든 숫자는 0~10000 까지 중에 랜덤한 값
연산자 당 괄호가 생성될 확률은 30%
사용할 연산자들은 +-*/
generator.py
from random import randrange, choice
def _test(ops: int, max_: int, bk: int, types: str):
"""
>>> _test(ops=100, max_=10000, bk=30, types="+-*/")
True
"""
result = create(ops=ops, max_=max_, bk=bk, types=types)
count_ops = sum([result.count(x) for x in types])
in_range_num = max([int(x) for x in result if x.isdigit()])
is_types = not bool([x for x in result if x in "+-*/" and x not in types])
if count_ops == ops and in_range_num < max_ and is_types:
return True
return False
def _unit(max_: int, bk: int, types: str)->list:
s = [str(randrange(1, max_)), choice(types), str(randrange(1, max_))]
return ["(", *s, ")"] if randrange(100) < bk else s
def _push(i: int, r: list, max_: int, bk: int, types: str)->list:
return r[:i] + _unit(max_, bk, types) + r[i + 1:]
def create(ops: int, max_: int, bk: int, types: str)->str:
r = ["0"]
for _ in range(ops):
i = choice([i for i, c in enumerate(r) if c.isdigit()])
r = _push(i, r, max_, bk, types)
return "".join(r)
if __name__ == '__main__':
import doctest
doctest.testmod()
main.py
from functools import wraps
import generator
import unittest
def _handler(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except AssertionError as e:
return e
except ZeroDivisionError as e:
return e
except SyntaxError as e:
return e
return wrapper
def _operator(ns: list)->str:
ns[0], ns[2] = float(ns[0]), float(ns[2])
func = {"+": lambda: ns[0] + ns[2],
"-": lambda: ns[0] - ns[2],
"*": lambda: ns[0] * ns[2],
"/": lambda: ns[0] / ns[2]}[ns[1]]
return str(func())
def _compile(os: str, r: list, i=0)->list:
while os[0] in r or os[1] in r:
if r[i] in os:
r = [*(r[:i-1]), _operator(r[i - 1:i + 2]), *(r[i + 2:])]
i -= 1
i += 1
return r
def _compile_all(r: list, tks=("*/", "+-"))->str:
for tk in tks:
r = _compile(tk, r)
return r[0]
def _progress(r: list, i=0)->str:
st = []
while "(" in r and ")" in r:
if r[i] == "(":
st += [i+1]
elif r[i] == ")":
if len(st):
j = st.pop()
t = r[j:i]
r = r[:j-1] + [_compile_all(t)] + r[i + 1:]
i -= len(t) + 2
i += 1
return _compile_all(r)
def _collect_digit(s: str, bf="")->list:
r = []
for c in s:
if c.isdigit() or c is '.':
bf += c
else:
r += [bf, c] if bf else [c]
bf = ""
r += [bf] if bf else []
return r
def _filter(s: str, tks=("",))->str:
for tk in tks:
s = s.replace(tk, "")
return s
def _is_syntax(s: str, patterns_syntax=("[\\d][\\s]+[\\d]", "[-+*/][\\s]*[-+*/]"))->bool:
import re
for t in patterns_syntax:
p = re.compile(t)
if bool(p.findall(s)):
return False
return True
def _is_bracket(s: str)->bool:
st = []
for c in s:
if c == "(":
st += [c]
elif c == ")":
if bool(st):
st.pop()
else:
return False
return not bool(st)
def _is_valid(s: str)->None:
if not _is_syntax(s) or not _is_bracket(s):
raise SyntaxError("Invalid syntax")
@_handler
def calculator(s: str)->float:
"""
calculator from equation
:param s: equation string
:return: answer is float
"""
_is_valid(s)
result = _filter(s)
result = _collect_digit(result)
result = _progress(result)
return float(result)
@_handler
def eval_(s):
return float(eval(s))
class Test(unittest.TestCase):
threshold_rate = 0.00000000001
def _chk_rate(self, a, b):
error_rate = abs(a - b) / a
self.assertTrue(error_rate < Test.threshold_rate)
def test_operator(self):
inputs = ( ["1", "+", "2"], ["2", "-", "3.55"], ["5", "*", "2.1"], ["123.123", "/", "234"])
answers = ('3.0', "-1.55", '10.5', '0.5261666666666667')
for input_, answer in zip(inputs, answers):
self._chk_rate(float(_operator(input_)), float(answer))
def test_collect_digit(self):
input_ = ("((1+2)-(3+4)/5555+2-3.4123123+5.6234324)",)
answer = ('1', '2', '3', '4', '5555', '2', '3.4', '5.6')
numbers = [c for c in _collect_digit(input_[0]) if c.isdigit()]
for o, a in zip(numbers, answer):
self.assertEqual(o, a)
def test_is_bracket(self):
wrong_cases = ("())", "((())", "))((", ")))()()", "(()()(())")
right_cases = ("((()()))", "()()()", "((()))((()))")
for right, wrong in zip(right_cases, wrong_cases):
self.assertTrue(_is_bracket(right))
self.assertFalse(_is_bracket(wrong))
def test_calculator(self):
for _ in range(100):
cmd = generator.create(ops=100, max_=10000, bk=30, types="+-*/")
a = calculator(cmd)
b = eval_(cmd)
self._chk_rate(a, b)
if __name__ == '__main__':
unittest.main()
'python lecture > project' 카테고리의 다른 글
[edu] sqlite3 import/export to csv (0) | 2019.02.07 |
---|---|
[edu] 가위바위보 게임 (랜덤, 확률, 결과 예측) (0) | 2019.01.10 |
[edu] 연락처 (push, pull, csv) (0) | 2018.12.31 |
[edu] 계산기 (사칙연산, 괄호, 입력식 오류 처리) (0) | 2018.12.28 |
[edu] Crawling (0) | 2018.08.29 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- PuTTYGen
- 모바일 스킨 적용
- 모바일 테마 적용
- 파이썬
- 장고 플러스친구 자동응답
- gitignore
- 문과 코딩
- django chatbot
- 파이썬 강좌
- 면접답변
- gitlab
- Tistory
- chatbot
- 면접정답
- 문서 비교
- django
- pycrypto
- wsgi
- virtualenv
- 파이썬 입문
- 엑셀 비교
- admin.py
- GIT
- 플러스친구 자동응답
- 파이썬 독학
- 파이썬 프로그래밍
- 장고 카톡 자동응답
- Python
- 장고
- 이미지 비교
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
글 보관함