AI文本科学计算器(calculator-sihui-python)混合四则运算介绍

一.科学计算器与混合四则运算(calculator-sihui)概述

       计算是一个十分重要的技能(Calculate and Compute),语音转文本后的混合四则运算(the four fundamental operations of arithmetic),或者是更加高级点的是十分必要的,尤其是在这个人工智能迅猛发展的今天。

       语音转文本暂且不提,AI时代语音助手只会简单的四则运算似乎也太low了,所以有了思慧计算器(calculator-sihui)。

       思慧计算器(calculator-sihui)设计思路如下:

               1. 可设置规则提取意图和操作符,这种就简单了,而且可变长度的操作符也不好设置规则,所以有一个可以确定是计算意图的数字和操作符就好,最好是先分类或者是规则确定意图;

               2. 接着就是文本转成标准算式,考虑到有科学计算(也就是超出加减乘除混合四则运算的部分),这部分先计算(这个以操作符+-*/等分隔开),这里要考虑冗余文本-汉语阿拉伯混合数字干扰;然后就是括号里边的先计算。

               3. 最后就是压入通用的string算式计算器,这个简单。

               github地址: https://github.com/yongzhuo/Tookit-Sihui/tree/master/tookit_sihui/task/calculator_sihui

二.calculator-sihui代码

     calculator-sihui代码分为4部分: 

        1. calcultor_formula.py  :  标准文本混合四则运算器, 只能计算混合四则运算, 例:输入"1+2+3", 输出"6"
        2. calcultor_function.py :  科学计算函数(超出加减乘除部分, 例如乘方, 开方, 指数, 对数, 阶乘等)
        3. calcultor_number.py   : 转化并提取文本中的阿拉伯数字
        4. calcultor_sihui.py    :  集成计算器

      2.1  calcultor_formula.py

# -*- coding: UTF-8 -*-
# !/usr/bin/python
# @time     :2019/8/21 23:38
# @author   :Mo
# @function :calcultor of text, not filter and redundancy 


from tookit_sihui.conf.logger_config import get_logger_root
import re


logger = get_logger_root()


def change_symbol(formula):
    """
        提取负号
        eg:-9-2-5-2*3-5/3-40*4/-1.0/5+6*3  ===>  -(9+2+5+2*3+5/3+40*4/1.0/5-6*3)
    :param formula: 
    :return: 
    """
    def primary_change(for_str):  # 把算式中的全角 + - 对应换成 - +
        temp = for_str.split("+")
        new_formula = []
        for value in temp:
            value = value.replace("-", "+")
            new_formula.append(value)
        return "-".join(new_formula)

    if formula.startswith("-"):
        formula = formula.replace("-", "", 1)
        formula = primary_change(formula)
        formula = formula.join(["-(", ")"])
    elif formula.startswith("+"):
        formula = primary_change(formula)
        formula = formula.join(["-(", ")"])
    else:
        formula = primary_change(formula)
        formula = formula.join(["-(-", ")"])
    return formula


def remove_repeat(formula):
    """
        去掉连续的重复的运算符
    :param formula: str, like: "1++2"
    :return: str, like:"1+2"
    """
    temp = formula.replace("++", "+")
    temp = temp.replace("+-", "-")
    temp = temp.replace("-+", "-")
    temp = temp.replace("--", "+")
    temp = temp.replace("*+", "*")
    temp = temp.replace("+*", "*")
    temp = temp.replace("/+", "/")
    temp = temp.replace("+/", "/")
    return temp


def has_special_operator(formula, special_operator):
    """
        判断是否有 *+ +- /- 之类的运算符
    :param formula: 
    :param special_operator: 
    :return: 
    """
    for operator in special_operator:
        if formula.find(operator) != -1:
            return operator
    return ""


def handle_special_operator(formula, operator):
    """
        如果有 "*-", "-*", "/-", "-/" 这些运算符,
        提取负号,去掉重复的运算符
    :param formula: 
    :param operator: 
    :return: 
    """
    temp = ""
    regex = "\d*[.]?\d+"
    opera = operator.replace("*", "[*]")
    ret = re.compile(opera.join([regex, regex]))
    while ret.search(formula):
        search_res = ret.search(formula).group()
        if operator.find("*") != -1:
            temp = search_res.replace(operator, "*")
        elif operator.find("/") != -1:
            temp = search_res.replace(operator, "/")
        temp = "-".join(["", temp])
        formula = formula.replace(search_res, temp, 1)
    return formula


def has_parentheses(formula):
    """
        判断是否还有括号
    :param formula: str
    :return: boolean
    """
    if re.search("[()]", formula):
        return True
    return False


def judge_illegal(formula):
    """
        判断括号是否匹配完全,运算符是否合法
        没有考虑  **  //  的计算
    :param formula: str
    :return: str
    """
    if len(re.findall("[(]", formula)) != len(re.findall("[)]", formula)):
        return True
    if formula.startswith("*") or formula.startswith("/"):
        return True
    if has_special_operator(formula, ["*/", "/*", "**", "//"]):
        return True
    return False


def calculator_formula(formula):
    """
        计算算式,这里计算的是不带括号的算式
    计算次序是 / * - +
    计算过程中出现括号则停止计算,返回当前的算式
    :param formula: 
    :return: 
    """
    def primary_operator(for_str, operation):
        try:
            primary_result = 0
            regex = "\d*[.]?\d*"
            ret = re.compile(operation.join(["[", "]"]).join([regex, regex]))
            while ret.search(for_str):
                ret_opera = has_special_operator(for_str, ["*-", "-*", "/-", "-/"])
                while ret_opera:
                    for_str = handle_special_operator(for_str, ret_opera)
                    ret_opera = has_special_operator(for_str, ["*-", "-*", "/-", "-/"])
                while has_special_operator(for_str, ["+-", "-+", "++", "--", "+*", "*+", "+/", "/+"]):
                    for_str = remove_repeat(for_str)
                # print("primary_operator:", for_str)
                if has_parentheses(for_str):
                    return for_str
                if for_str.startswith("-"):
                    temp = re.findall("^-\d*[.]?\d*$", for_str)
                    if temp:
                        return temp[0]
                    return change_symbol(for_str)
                if for_str.startswith("+"):
                    for_str = for_str.replace("+", "", 1)
                if not ret.search(for_str):
                    continue
                search_res = ret.search(for_str).group()
                operand_list = search_res.split(operation)
                if operation == "/":
                    primary_result = float(operand_list[0]) / float(operand_list[1])
                elif operation == "*":
                    primary_result = float(operand_list[0]) * float(operand_list[1])
                elif operation == "-":
                    primary_result = float(operand_list[0]) - float(operand_list[1])
                elif operation == "+":
                    primary_result = float(operand_list[0]) + float(operand_list[1])
                for_str = for_str.replace(search_res, '%f' % (primary_result), 1)
            return for_str
        except Exception as e:
            logger.info(str(e))
            return None
    try:
        formula = primary_operator(formula, "/")
        formula = primary_operator(formula, "*")
        formula = primary_operator(formula, "-")
        formula = primary_operator(formula, "+")
    except Exception as e:
        logger.info(str(e))
        return None
    return formula


def remove_parentheses(formula):
    """
        去掉算式的括号,计算括号里算式
    :param formula: 
    :return: 
    """
    parentheses = re.compile("\([^()]+\)")
    while parentheses.search(formula):
        search_res = parentheses.search(formula).group()
        for_str = re.sub("[()]", "", search_res)
        if judge_illegal(for_str):
            return ""
        for_str = calculator_formula(for_str)
        formula = formula.replace(search_res, for_str, 1)
    """
    会有去掉所有括号算式还没算完的情况
    eg:1-2*65
    需要再计算一遍算式
    """
    formula = calculator_formula(formula)
    return formula


def result_formula(formula):
    """  
        简单计算器, 纯粹四则运算
        去完括号后额外计算的那一次若再次出现括号,
        则重复去括号运算,直至再没有括号
    :param formula: str
    :return: str
    """

    def remove_space(formula):
        """
            去掉算式的空格
        :param formula: str
        :return: str
        """
        return formula.replace(" ", "")

    def first_calculator(for_str):
        """
            先计算括号里边的
        :param for_str: 
        :return: 
        """
        if judge_illegal(for_str):
            return None
        return remove_parentheses(for_str)

    formula = remove_space(formula)

    formula = first_calculator(formula)
    if not formula:
        return None
    while has_parentheses(formula):
        formula = first_calculator(formula)
        # print("calculator_result:", formula)
    if not formula:
        return None
    return formula


if __name__ == '__main__':
    cal = result_formula("1+1+2+3*(35+1-5*7-10/5)/2*2")
    print(cal)

      2.2  calcultor_function.py

# -*- coding: UTF-8 -*-
# !/usr/bin/python
# @time     :2019/8/21 23:36
# @author   :Mo
# @function :function of some basic Extraction Scientific Computing


from tookit_sihui.task.calculator_sihui.calcultor_number import extract_number
from tookit_sihui.conf.logger_config import get_logger_root
import math


logger = get_logger_root()


def reagan(words, wordsminus):
    """
        求平方根,立方根,n次方根
    :param words: str, 原句
    :param wordsminus:str , 处理后的句子
    :return: 
    """
    try:
        if '根号' in words:
            reagan = wordsminus.replace("开", "").replace("根号", "").replace("的", "")
            radicalaa = float(extract_number(reagan)[0])
            if radicalaa < 0.0:
                return 'illegal math'
            radicalbb = math.sqrt(radicalaa)
            results = str(radicalbb)
        elif "平方根" in words:
            reagan = wordsminus.replace("开", "").replace("平方根", "").replace("平方", "").replace("的", "")
            reagan = extract_number(reagan)[0]
            squarerootaa = float(reagan)
            if squarerootaa < 0.0:
                return 'illegal math'
            squarerootbb = math.sqrt(squarerootaa)
            results = str(squarerootbb)
        elif "立方根" in words:
            reagan = wordsminus.replace("开", "").replace("立方根", "").replace("立方", "").replace("的", "")
            reagan = extract_number(reagan)[0]
            squarerootaa = float(reagan)
            squarerootbb = math.pow(squarerootaa, 1.0 / 3)
            results = str(squarerootbb)
        elif "次方根" in words:
            reagan = wordsminus.replace("开", "").replace("次方根", "").replace("次方", "")
            squareroot = reagan.split("的")
            squarerootaa = float(extract_number(squareroot[0])[0])
            squarerootbb = float(extract_number(squareroot[1])[0])
            if squarerootaa % 2 == 0 and squarerootbb < 0.0:
                return 'illegal math'
            squarerootcc = math.pow(squarerootaa, 1.0 / squarerootbb)
            results = str(squarerootcc)
        else:
            results = words
        return results
    except Exception as e:
        logger.info(str(e))
        return words


def power(words, wordsminus):
    """
        求指数,求平方
    :param words: 
    :param wordsminus: 
    :return: 
    """
    try:
        if "平方根" not in words and "平方" in words:
            reagan = wordsminus.replace("平方", "").replace("开", "").replace("的", "")
            reagan = extract_number(reagan)[0]
            square = float(reagan)
            radicalbb = math.pow(square, 2)
            results = str(radicalbb)
        elif "立方根" not in words and "立方" in words:
            reagan = wordsminus.replace("立方", "").replace("开", "").replace("的", "")
            reagan = extract_number(reagan)[0]
            square = float(reagan)
            radicalbb = math.pow(square, 3)
            results = str(radicalbb)
        elif (("次方" in words or "次幂" in words) and "次方根" not in words and "次幂根" not in words):
            reagan = wordsminus.replace("次方", "").replace("开", "").replace("次幂", "")
            squareroot = reagan.split("的")
            squarerootaa = float(extract_number(squareroot[0])[0])
            squarerootbb = float(extract_number(squareroot[1])[0])
            squarerootcc = math.pow(squarerootaa, squarerootbb)
            results = str(squarerootcc)
        else:
            results = words
        return results
    except Exception as e:
        logger.info(str(e))
        return words


def logarithm(words, wordsminus):
    """
        求对数
    :param words: 
    :param wordsminus: 
    :return: 
    """
    try:
        if "LG" in words or "LOG" in words:
            Lg = wordsminus.replace("LOG", "").replace("LG", "").replace(" ", "").replace("的", "")
            Lg = float(extract_number(Lg)[0])
            if Lg <= 0.0:
                return 'illegal math'
            lgbb = math.log(Lg)
            results = str(lgbb)
        elif "对数" in words:
            Logg = wordsminus.replace("以", "").replace("对数", "").replace("的对数", "").replace(" ", "").replace("的", "")
            root = Logg.split("为底")
            rootaa = float(extract_number(root[0])[0])
            rootbb = float(extract_number(root[1])[0])
            if rootaa <= 0.0 or rootbb <= 0.0:
                return 'illegal math'
            rootcc = math.log(rootbb) / math.log(rootaa)
            results = str(rootcc)
        else:
            results = words
        return results
    except Exception as e:
        logger.info(str(e))
        return words


def fraction(words, wordsminus):
    """
        求分数
    :param words: 
    :param wordsminus: 
    :return: 
    """
    try:
        if "fenzhi" in words:
            fenzhi = wordsminus.replace("fenzhi", "/").replace(" ", "").replace("的", "")
            root = fenzhi.split("/")
            rootaa = float(extract_number(root[0])[0])
            rootbb = float(extract_number(root[1])[0])
            rootcc = rootbb / rootaa
            results = str(rootcc)
        else:
            results = words
        return results
    except Exception as e:
        logger.info(str(e))
        return words


def fractiontwo(words, wordsminus):
    """
        取分数
    :param words: 
    :param wordsminus: 
    :return: 
    """
    try:
        if "fenzhi" in words:
            fenzhi = wordsminus.replace("fenzhi", "/").replace(" ", "").replace("的", "")
            root = fenzhi.split("/")
            rootaa = float(extract_number(root[0])[0])
            rootbb = float(extract_number(root[1])[0])
            results = str(rootaa) + "/" + str(rootbb)
        else:
            results = words
        return results
    except Exception as e:
        logger.info(str(e))
        return words


def factorial(words, wordsminus):
    """
        求阶乘
    :param words: 
    :param wordsminus: 
    :return: 
    """
    results = words
    try:
        if "jiecheng的" in words:
            factory = wordsminus.replace("jiecheng的", "").replace("的", "").replace(" ", "")
            fact = float(extract_number(factory)[0])
            if fact <= 10000:
                results = str(math.factorial(fact))
            else:
                results = words
        return results
    except Exception as e:
        logger.info(str(e))
        return words


if __name__ == '__main__':
    res = reagan("根号4", "根号4")
    print(res)
    res = reagan("27的3次方根是多少", "27的3次方根")
    print(res)
    res = power("9的平方", "9的平方")
    print(res)
    res = power("27的立方是几", "9的立方")
    print(res)
    res = power("3的3次方是几", "3的3次方实")
    print(res)
    res = logarithm("LG8", "LG8")
    print(res)
    res = logarithm("以2为底64的对数", "以2为底64的对数")
    print(res)
    res = fraction("1fenzhi6是多少", "1fenzhi6")
    print(res)
    res = factorial("10jiecheng的", "10jiecheng的")
    print(res)

      2.3  calcultor_number.py

# -*- coding: UTF-8 -*-
# !/usr/bin/python
# @time     :2019/8/22 0:09
# @author   :Mo
# @function :extract number from sentence of chinese or mix。提取数字,中文,或者混合中文-阿拉伯数字


import regex as re

# * 字符串预处理模块,为分析器TimeNormalizer提供相应的字符串预处理服务
class StringPreHandler:
    # @Author  : zhm
    # @codes   : code from github: https://github.com/zhanzecheng/Time_NLP
    # @function :StringPreHandler.py
    @classmethod
    def delKeyword(cls, target, rules):
        """
        该方法删除一字符串中所有匹配某一规则字串
        可用于清理一个字符串中的空白符和语气助词
        :param target: 待处理字符串
        :param rules: 删除规则
        :return: 清理工作完成后的字符串
        """
        pattern = re.compile(rules)
        res = pattern.sub('', target)
        # print res
        return res


    @classmethod
    def numberTranslator(cls, target):
        """
        该方法可以将字符串中所有的用汉字表示的数字转化为用阿拉伯数字表示的数字
        如"这里有一千两百个人,六百零五个来自中国"可以转化为
        "这里有1200个人,605个来自中国"
        此外添加支持了部分不规则表达方法
        如两万零六百五可转化为20650
        两百一十四和两百十四都可以转化为214
        一六零加一五八可以转化为160+158
        该方法目前支持的正确转化范围是0-99999999
        该功能模块具有良好的复用性
        :param target: 待转化的字符串
        :return: 转化完毕后的字符串
        """
        pattern = re.compile(u"[一二两三四五六七八九123456789]万[一二两三四五六七八九123456789](?!(千|百|十))")
        match = pattern.finditer(target)
        for m in match:
            group = m.group()
            s = group.split(u"万")
            s = list(filter(None, s))
            num = 0
            if len(s) == 2:
                num += cls.wordToNumber(s[0]) * 10000 + cls.wordToNumber(s[1]) * 1000
            target = pattern.sub(str(num), target, 1)

        pattern = re.compile(u"[一二两三四五六七八九123456789]千[一二两三四五六七八九123456789](?!(百|十))")
        match = pattern.finditer(target)
        for m in match:
            group = m.group()
            s = group.split(u"千")
            s = list(filter(None, s))
            num = 0
            if len(s) == 2:
                num += cls.wordToNumber(s[0]) * 1000 + cls.wordToNumber(s[1]) * 100
            target = pattern.sub(str(num), target, 1)

        pattern = re.compile(u"[一二两三四五六七八九123456789]百[一二两三四五六七八九123456789](?!十)")
        match = pattern.finditer(target)
        for m in match:
            group = m.group()
            s = group.split(u"百")
            s = list(filter(None, s))
            num = 0
            if len(s) == 2:
                num += cls.wordToNumber(s[0]) * 100 + cls.wordToNumber(s[1]) * 10
            target = pattern.sub(str(num), target, 1)

        pattern = re.compile(u"[零一二两三四五六七八九]")
        match = pattern.finditer(target)
        for m in match:
            target = pattern.sub(str(cls.wordToNumber(m.group())), target, 1)

        pattern = re.compile(u"(?<=(周|星期))[末天日]")
        match = pattern.finditer(target)
        for m in match:
            target = pattern.sub(str(cls.wordToNumber(m.group())), target, 1)

        pattern = re.compile(u"(?<!(周|星期))0?[0-9]?十[0-9]?")
        match = pattern.finditer(target)
        for m in match:
            group = m.group()
            s = group.split(u"十")
            num = 0
            ten = cls.strToInt(s[0])
            if ten == 0:
                ten = 1
            unit = cls.strToInt(s[1])
            num = ten * 10 + unit
            target = pattern.sub(str(num), target, 1)

        pattern = re.compile(u"0?[1-9]百[0-9]?[0-9]?")
        match = pattern.finditer(target)
        for m in match:
            group = m.group()
            s = group.split(u"百")
            s = list(filter(None, s))
            num = 0
            if len(s) == 1:
                hundred = int(s[0])
                num += hundred * 100
            elif len(s) == 2:
                hundred = int(s[0])
                num += hundred * 100
                num += int(s[1])
            target = pattern.sub(str(num), target, 1)

        pattern = re.compile(u"0?[1-9]千[0-9]?[0-9]?[0-9]?")
        match = pattern.finditer(target)
        for m in match:
            group = m.group()
            s = group.split(u"千")
            s = list(filter(None, s))
            num = 0
            if len(s) == 1:
                thousand = int(s[0])
                num += thousand * 1000
            elif len(s) == 2:
                thousand = int(s[0])
                num += thousand * 1000
                num += int(s[1])
            target = pattern.sub(str(num), target, 1)

        pattern = re.compile(u"[0-9]+万[0-9]?[0-9]?[0-9]?[0-9]?")
        match = pattern.finditer(target)
        for m in match:
            group = m.group()
            s = group.split(u"万")
            s = list(filter(None, s))
            num = 0
            if len(s) == 1:
                tenthousand = int(s[0])
                num += tenthousand * 10000
            elif len(s) == 2:
                tenthousand = int(s[0])
                num += tenthousand * 10000
                num += int(s[1])
            target = pattern.sub(str(num), target, 1)

        return target

    @classmethod
    def wordToNumber(cls, s):
        """
        方法numberTranslator的辅助方法,可将[零-九]正确翻译为[0-9]
        :param s: 大写数字
        :return: 对应的整形数,如果不是数字返回-1
        """
        if (s == u'零') or (s == '0'):
            return 0
        elif (s == u'一') or (s == '1'):
            return 1
        elif (s == u'二') or (s == u'两') or (s == '2'):
            return 2
        elif (s == u'三') or (s == '3'):
            return 3
        elif (s == u'四') or (s == '4'):
            return 4
        elif (s == u'五') or (s == '5'):
            return 5
        elif (s == u'六') or (s == '6'):
            return 6
        elif (s == u'七') or (s == u'天') or (s == u'日') or (s == u'末') or (s == '7'):
            return 7
        elif (s == u'八') or (s == '8'):
            return 8
        elif (s == u'九') or (s == '9'):
            return 9
        else:
            return -1

    @classmethod
    def strToInt(cls, s):
        try:
            res = int(s)
        except:
            res = 0
        return res


sph = StringPreHandler()


def extract_number(sentence):
    """
        提取数字,纯数字
    :param sentence: str
    :return: list<str>
    """
    res = sph.numberTranslator(target=sentence)
    find_list = []
    for i in re.finditer('(\d+(\.\d+)?)', res):
        find_list.append(i.group())
    return find_list

if __name__ == '__main__':
    sen = "1000.一加1等于几"
    res = extract_number(sen)
    print(res)

      2.4  calcultor_sihui.py

# -*- coding: UTF-8 -*-
# !/usr/bin/python
# @time     :2019/8/21 10:22
# @author   :Mo
# @function :an ai text calcultor of xiaomo


from tookit_sihui.task.calculator_sihui.calcultor_function import reagan, power, logarithm, fraction, factorial, fractiontwo
from tookit_sihui.task.calculator_sihui.calcultor_number import extract_number, sph
from tookit_sihui.task.calculator_sihui.calcultor_formula import result_formula
from tookit_sihui.conf.logger_config import get_logger_root
import re


logger = get_logger_root()


def StringToCalculateZero(words=''):
    """
        混合运算去除非计算式等无用词
    :param words: str
    :return: str
    """
    wordsspot = words.replace("点", ".")
    wordsmark = wordsspot.replace("分之", "/")
    wordsin = wordsmark.replace("正切", "zheng切").replace("正弦", "zheng弦").replace("正割", "zheng割").replace("正矢", "zheng矢")
    wordsadd = wordsin.replace("加上", "+").replace("加到", "+").replace("加", "+").replace("+", "+").replace("正", "+")
    wordsminus = wordsadd.replace("减去", "-").replace("减", "-").replace("-", "-").replace("负", "-")
    wordsmult = wordsminus.replace("阶乘", "jiecheng的").replace("乘上", "*").replace("乘以", "*").replace("乘于","*").replace("乘", "*").replace("×", "*")
    wordsdivis01 = wordsmult.replace("除去", "/").replace("除以", "/").replace("除于", "/").replace("除","/").replace("÷", "/")
    wordsdivis02 = wordsdivis01.replace("从", "").replace("再", "").replace("在", "").replace("然后", "").replace("直", "").replace("到", "")
    formula = wordsdivis02.replace("左括号", "(").replace("右括号", "(").replace("的和", "").replace("的差", "").replace("的商", "").replace("的积", "")
    myformula = formula.replace("*-", "*(-1)*").replace("\\*\\+", "*").replace("\\/\\-", "/(-1)/")
    stringtocalculatezero = myformula.replace(" ", "").replace("\\+\\-", "\\-").replace("\\+\\+", "\\+").replace("\\-\\+", "\\-").replace("\\-\\-", "\\+")

    return stringtocalculatezero


def StringToCalculateOne(words):
    """
        简单句总调用
        求乘方,阶乘,指数,根式,三角函数,对数,最大最小公约数公倍数    
    :param words: str
    :return: str
    """
    try:
        res_reagan = reagan(words, words)  # 报错或不执行返回原来的数据
        res_power = power(words, words)
        # aa22 = triangle(complex[i], complex[i])
        res_logarithm = logarithm(words, words)
        rees_factorial = factorial(words, words)
        res_fraction = fraction(words, words)
        if (res_reagan != words):
            goal = res_reagan
        elif (res_power != words):
            goal = res_power
        # elif (aa22 != complex[i]):
        #     goal = aa22
        elif (res_logarithm != words):
            goal = res_logarithm
        elif (rees_factorial != words):
            goal = rees_factorial
        elif (res_fraction != words):
            goal = res_fraction
        else:
            oldwords = words.replace("的", "")
            oldwords = extract_number(oldwords)[0]
            goal = oldwords
        return goal
    except Exception as e:
        logger.info(str(e))
        return words


def StringToCalculateTwo(sentence=''):
    """
        复杂算式, 总调用, 分步计算,先计算三角函数,指数,对数
        1.取出操作符与数据(注意--,++,-,+开头这种)
        2.计算中间的,比如说根号12,2的7次方这种
    :param sentence: 
    :return: 
    """
    try:
        if sentence[0] == '+' or sentence[0] == '-':
            sentence = '0' + sentence
        minus = 0
        operators = []
        complex = re.split("[+*/-]", sentence)
        for s in sentence:
            if ((s == '+' or s == '-' or s == '*' or s == '/') & minus != 0 & minus != 2):
                operators.append("" + s)
                minus = minus + 1
            else:
                minus = 1
        # complex.append(float(formula[prePos:].strip()))
        formula = ""
        for i in range(len(complex)):
            if "" == complex[i]:
                complex[i] = " "
                formula = formula + complex[i] + operators[i]
                continue
            res_reagan = reagan(complex[i], complex[i]) #报错或不执行返回原来的数据
            res_power = power(complex[i], complex[i])
            # aa22 = triangle(complex[i], complex[i])
            res_logarithm = logarithm(complex[i], complex[i])
            res_factorial = factorial(complex[i], complex[i])
            res_fraction = fraction(complex[i], complex[i])

            if (res_reagan != complex[i]):
                goal = res_reagan
            elif (res_power != complex[i]):
                goal = res_power
            # elif (aa22 != complex[i]):
            #     goal = aa22
            elif (res_logarithm != complex[i]):
                goal = res_logarithm
            elif (res_factorial != complex[i]):
                goal = res_factorial
            elif (res_fraction != complex[i]):
                goal = res_fraction
            elif "(" in complex[i] or ")" in complex[i]:
                goal = sph.numberTranslator(target=complex[i].replace("的", ""))
            else:
                oldwords = complex[i].replace("的", "")
                oldwords = extract_number(oldwords)[0]
                goal = oldwords
            if goal == 'illegal math': #非法抛出
               return 'illegal math'
            if (i < len(complex) - 1):
                rest = goal + operators[i]
            else:
                rest = goal
            formula = formula + rest
        myformula = formula.replace("*-", "*(-1)*").replace("*+", "*").replace("/-", "/(-1)/")
        formulalast = myformula.replace(" ", "").replace("+-", "-").replace("++", "+").replace("-+", "-").replace("--","+")
    except Exception as e:
        logger.info(str(e))
        return sentence

    return formulalast


def calculator_sihui(sentence = ''):
    """
        思慧计算器总调用接口
    :param sentence:str, 输入句子,TEXT 
    :return: 
    """
    # 运算符转换
    sentence_wise    = StringToCalculateZero(sentence)
    # 混合运算
    sentence_replace = StringToCalculateTwo(sentence_wise)
    if ('/0' in sentence_replace and '/0.' not in sentence_replace) or sentence_replace == 'illegal math':
        return 'illegal math'
    for char in sentence_replace:
        if char not in '+-*/().0123456789':
            return 'could not calculate'
    #
    result = result_formula(sentence_replace)
    return result


if __name__ == "__main__":
    equation_sample = [
            '1+2等于几',
            '100+30',
            '111+90-9等于几',
            "23 + 13 * ((25+(-9-2-5-2*3-6/3-40*4/(2-3)/5+6*3) * (9-2*6/3 + 5 *3*9/9*5 +10 * 56/(-14) )) - (-4*3)/ (3+3*3) )",
            '1-2-3-4-5-6',
            '134+123*898*123456789212310',
            '4*5*6/6/5',
            '(1+(2+(3-(4*6/4/3)-1)-1)-3)+(6-7)',
            '1+1+1',
            '1*1*2',
            '1+2+3+4+6',
            '1/2+2*3*4*5/5/4-1',
            '1+2(12/13)',
            '1+2+3+4+5+6+7+8+9+10',
            '-1+1+2+(-2)',
            '((-3)*2+1/2-3*4/4) +1',
            'LG0',
            'LOG100',
            '以2为底4的对数',
            '根号一百二十三加上1',
            '1加2的根号',
            '根号1加2的和',
            '以2为底4的对数',
            '2的六次方',
            '2的3次幂',
            '二的一次方',
            '四的平方',
            '十一的立方',
            '开11的立方根',
            '开3的7次方根',
            '13的阶乘',
            '根号四',
            '1除以0',

            '负一加上100加上50000',
            '2的8次方减6',
            '根号5乘以90',
            '2的8次方减6',
            '1的平方加根号2',
            '30的阶乘加90',
            '二分之一加1/3',
        ]

    for es in equation_sample:
        print('ff算式: ' + es)
        print('思慧计算器结果: ' + str(calculator_sihui(es)))

希望对你有所帮助!

发布了96 篇原创文章 · 获赞 72 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/rensihui/article/details/100006554