最近用python实现了真值表,经过有点儿曲折,刚开始没考虑优先级,直到前天才发现这个问题(离散数学没学好啊),用栈改了一下。话说python就是强,把列表类型当栈用,直接调用列表的pop()和append()非常方便,废话少说上代码(命令行版)。

  1. 首先是导入外部库和定义函数
#导入正则表达式re库,用来从字符串中提取信息
import re
#prettytable库帮我们打印出漂亮的表格
from prettytable import PrettyTable

#过滤掉(
def filter_brackets(string):
    p=re.compile(r'[(]+(.*)')
    return(p.findall(string)[0])

#判断格式是否合理,并返回真值表的列名
def to_show(string):
    #利用patten提取括号中的内容
    patten=re.compile(r'[(](.*?)[)]')
    contents_in_brackets=patten.findall(string)
    #contents_in_brackets中的元素存在'('的现象,故对所有元素进行遍历过滤掉这些括号
    for i in range(len(contents_in_brackets)):
        if contents_in_brackets[i].startswith('('):
            contents_in_brackets[i]=filter_brackets(contents_in_brackets[i])
    
    #利用sp提取命题变元,n为命题变元的个数
    sp=re.compile('[a-zA-Z]')
    simple_exp=sp.findall(string)

    l=simple_exp+contents_in_brackets
    #l去重得到l1
    l1=[]
    for i in l:
        if i not in l1:
            l1.append(i)
    l1.append(string)
    l1.sort(key=len)
    #第一项是要展示的部分,第二项是命题变元(有重复)
    return([l1,simple_exp])
  1. 其次是运算部分
def get_prioty(operator):
    #if operator=='(' or operator==')'
    p=-1
    if operator=='(':
        p=6
    elif operator=='!':
        p=5
    elif operator=='&':
        p=4
    elif operator=='#':
        p=3
    elif operator=='|':
        p=2
    elif operator=='>':
        p=1
    elif operator=='=':
        p=0
    return(p)

#两命题变元运算
def cal(a,operator,b=-1):
    if operator == '!':
        boo = not a
    elif operator == '&':
        boo = a and b
    elif operator == '|':
        boo = a or b
    #异或
    elif operator == '#':
        boo = (a and (not b)) or ((b and (not a)))
    #条件(注意顺序是反的)
    elif operator == '>':
        boo = (not b) or a
    #等值
    elif operator == '=':
        boo = ((not a) and (not b)) or (a and b)
    else:
        print("there is no such operator")
        return(None)
    if(boo):
        return(1)
    else:
        return(0)

#对传入的字符串进行运算(传入的字符串无括号),且
def cal_str(Str,dic):
    i=0
    #s0为数字栈
    s0=[]
    #s1为运算符栈
    s1=[]
    while i<len(Str) or len(s1)!=0:
        if i<len(Str):
            c=Str[i]
        else:
            c=''
        if c.isalpha():
            s0.append(dic[c])
            i=i+1
        else:
            if len(s1)==0 or (c!=')' and s1[-1]=='(') or get_prioty(c)>=get_prioty(s1[-1]):
                s1.append(c)
                i=i+1
                continue

            if  c==')' and s1[-1]=='(':
                s1.pop()
                i=i+1
                continue
            
            if (i>=len(Str) and len(s1)!=0) or (c==')' and s1[-1]!='(') or get_prioty(c)<=get_prioty(s1[-1]):
                opt=s1.pop()
                if opt!='!':
                    result=cal(s0.pop(),opt,s0.pop())
                elif opt=='!':
                    result=cal(s0.pop(),opt)
                s0.append(result)
    return(s0[0])
  1. 利用bin()函数得到相应元素个数的全部真值赋值,经过一顿操作使用zip()函数将命题变元与其真值(0或1)绑定起来,遍历所有的真值赋值情况,计算每种真值情况下的各个表达式的值,得到真值表
#产生真值序列(字典形式)的列表
def gen_truth_list(elems):
    num=len(elems)
    tl=[]
    for i in range(2**num):
        st=bin(i)[2:].zfill(num)
        truth_list=list(map(lambda j:int(j),list(st)))
        #append:将字典以整体形式加到列表中
        tl.append(dict(zip(elems,truth_list)))
    return(tl)

def gen_all_line(truth_list,header):
    #产生真值表数据
    all_line=[]
    for line_truth in truth_list:
        per_line=[]
        for exp in header:
            truth=cal_str(exp,line_truth)
            per_line.append(truth)
        all_line.append(per_line)
    return(all_line)
  1. 根据真值表获得主范式
#返回一个小项
def get_minterm(term):
    if len(term)!=0:
        return('('+'&'.join(term)+')')
    else:
        return('')

#返回一个大项
def get_maxterm(term):
    if len(term)!=0:
        return('('+'|'.join(term)+')')
    else:
        return('')

def get_dnf(header,elems):
    truth_list=gen_truth_list(elems)
    minterms=[]
    all_line=gen_all_line(truth_list,header)
    #遍历每一行
    for line_id in range(2**len(elems)):
        #term为包含某小项中各命题变元正确形式的列表
        term=[]
        #如果该行的真值赋值使得表达式为1
        if all_line[line_id][-1]==1:
            #遍历该行对应的真值赋值
            for t in truth_list[line_id]:
                if truth_list[line_id][t]==1:
                    term.append(t)
                else:
                    term.append('!'+t)
        #表达式为1才能加入小项列表
        minterm=get_minterm(term)  
        if minterm!='':
            minterms.append(minterm)
    return('|'.join(minterms))

def get_cnf(header,elems):
    truth_list=gen_truth_list(elems)
    maxterms=[]
    all_line=gen_all_line(truth_list,header)
    #遍历每一行
    for line_id in range(2**len(elems)):
        term=[]
        #如果该行的真值赋值使得表达式为0
        if all_line[line_id][-1]==0:
            #遍历该行对应的真值赋值
            for t in truth_list[line_id]:
                if truth_list[line_id][t]==0:
                    term.append(t)
                else:
                    term.append('!'+t)
        #表达式为1才能加入小项列表
        maxterm=get_maxterm(term)  
        if maxterm!='':
            maxterms.append(maxterm)
    return('&'.join(maxterms))
  1. 主函数如下
if __name__=="__main__":
        #获取字符串
    string=input('input:')
    
    header=to_show(string)[0]
    elem=to_show(string)[1]
    elems=[]
    for i in elem:
        if i not in elems:
            elems.append(i)
    truth_list=gen_truth_list(elems)
    
    all_line=[]
    for line_truth in truth_list:
        per_line=[]
        for exp in header:
            truth=cal_str(exp,line_truth)
            per_line.append(truth)
        all_line.append(per_line)
    
    truth_table=PrettyTable(header)
    for line in all_line:
        truth_table.add_row(line)
    
    print('The truth table of this formula is printed below:')
    print(truth_table)
    
    continue_or_not=input('Show "principal disjunctive normal form" \n or  "principal conjunctive normal form"? [y/n]\n')
    #继续输出主范式
    if continue_or_not=='y':
        print('pdnf(主析取范式): '+get_dnf(header,elems))
        print('pcnf(主合取范式): '+get_cnf(header,elems))

第一次写技术博客,有点儿激动,先写到这,过两天给出一个GUI版本的。