如何用编程判断一个字符串是否是合适公式呢?以下提供两种思路:
PS:本文中 !否定,*合取,+析取,-条件,=双条件
一、老师的STL精简版本
简要步骤:
①把原子命题全部转换为字符1
②将特定字串(如(1)、!1、1+1等)转换为字符1
C++代码:
#include <iostream>
#include <cstring>
using namespace std;
int rps(string &str,string ss,string sd,int runum)
{
int i=str.length(),p;
while(p=str.find(ss)+1)
str.replace(p-1, ss.length(), sd);
if(str.length()!=i)
cout<<"使用规则"<<runum<<"后:"<<str<<endl;
return str.length()-i;
}
int main()
{
string str,strtmp;
cout<<"输入提示:"<<endl;
while(cin>>str)
{
strtmp=str;
for(int i=0; i<str.length(); i++)
if((str[i]>='a'&&str[i]<='z')||str[i]=='0')
str[i]='1';
cout<<"使用规则1后:"<<str<<endl;
while(rps(str,"!1","1",2)||rps(str,"(1)","1",2)||rps(str,"1+1","1",3)||rps(str,"1*1","1",3)||rps(str,"1-1","1",3)||rps(str,"1=1","1",3));
if(str=="1")
cout<<strtmp<<" is valid!"<<endl;
else
cout<<strtmp<<" is invalid!"<<endl;
}
return 0;
}
二、我自己的版本
步骤:
①处理括号,遇到括号则递归处理
②处理否定,把合法的!删除
③判断最后的字符串:即奇数位是原子命题,偶数位是联结词(除了!)
C++代码:
// !否定,*合取,+析取,-条件,=双条件
#include <iostream>
#include <cstring>
using namespace std;
bool isAtomic(char c) //判断是否为原子命题
{
if(isalpha(c)) return true;
if(c == '0' || c == '1') return true;
return false;
}
bool isConnect(char c) //判断是否为联结词(!除外)
{
if(c == '*' || c == '+' || c == '-' || c == '=' ) return true;
return false;
}
bool isLegal(string str) //公式是否合法
{
if(str.length() < 1) return false; //没有字符为非法
//【处理括号】
int pLeft = 0, // ( 的位置
pRight = 0, // ) 的位置
pCount = 0; //当前出现的(的个数 - 当前出现的)的个数
for(size_t i = 0; i < str.length(); ++i)
{
if(str[i] == '(') pLeft = i; //找到第一个(
else continue;
for(; i < str.length(); ++i) //百度:string.length()的时间效率是O(1)
{
if(str[i] == '(') ++pCount;
else if(str[i] == ')')
{
--pCount;
if(pCount == 0) //若是对应的)
{
pRight = i;
if(isLegal(str.substr(pLeft + 1, pRight - pLeft - 1)) == false) //递归地对括号内的内容进行判断
return false;
else //将(变为1,删除)和括号里的内容
{
str.at(pLeft) = '1';
str.erase(str.begin() + pLeft + 1, str.begin() + pRight + 1);
i = pLeft; //i变为pLeft
break;
}
}
}
}
if(pCount != 0) return false;
}
//【处理否定】
for(size_t i = 0; i < str.length(); ++i)
if(str[i] == '!')
{
if(i == str.length() - 1) return false; //!出现在最后一位
if(!isConnect(str[i+1])) //!后面不是联结词
{
str.erase(str.begin() + i); //删除!
--i;
}
else return false;
}
//【判断其它联结词】
for(size_t i = 0; i < str.length(); ++i) //第奇数个字符是原子命题,第偶数个是联结词
{
if(i&1 && !isConnect(str[i])) return false;
if(!i&1 && !isAtomic(str[i])) return false;
}
return true;
}
int main()
{
cout<<"请输入公式,!否定,*合取,+析取,-条件,=双条件:"<<endl;
string input;
while(cin>>input) //循环输入+判断
{
if(isLegal(input))
cout<<input<<" is legal."<<endl;
else cout<<input<<" is invalid."<<endl;
}
return 0;
}
注释比较详细,大家慢慢看喽~