用正则表达式(regex)匹配多项式(polynomial)
因为作业的要求,我需要识别用户从命令行输入的多项式,并且要提取出其中的系数、指数以便用于后续计算。
曾经想过用一个数组把用户所有的输入全部存进来,然后在写逻辑判断。但想想那复杂的逻辑,头皮都发麻,这时候因为有个朋友拜托我写个简单的小爬虫,写完后我灵机一动,爬虫用到的正则表达式不就是最好的处理手段么??(感谢同学,大雾)
言归正传。
首先先简单的讲一讲关于正则表达式的知识,这里就只关注那些我一会儿会用到的。
[ ] 方括号在这里被叫做原子表,它能够匹配括号中出现的任意一个元素
[abcd] //匹配abcd中任意一个字母
[!@#] // 匹配!@#中任意一个符号
[-] //匹配0,1,2,3,4,5,6,7,8,9中任意一个数字
三个常用的特殊符号: * + ?
- * 星号可以匹配前面出现的元素0次,1次或任意多次
- + 加号可以匹配前面出现的元素1次或任意多次
- ? 问号可以匹配前面出现的元素0次或1次
ab* //匹配 a,ab,abb,abbb.......
ab+ //匹配 ab,abb,abbb,abbbb.......
ab? //匹配 a,ab
( ) 圆括号在这里被叫做模式单元符,他能够将一些元素组合成一个大的,不可分割的新元素,类似于括号在正常运算中的作用。
(ab*)? //匹配 空串 或 a,ab,abb,abbb.......
(ab+)? //匹配 空串 或 ab,abb,abbb,abbbb.......
(ab?)? //匹配 空串 或 a,ab
匹配任意字符:.(除换行符)
a.c //匹配aac,abc,acc,adc.......
转义符 : 如果想要匹配本身拥有特殊意义的符号,可以使用转移符\
\. // 匹配一个小数点
边界限制字符:^ $
- ^ 匹配字符串的开始
- $ 匹配字符串的结束
^a.* //匹配以a开头的字符串
.*a$ //匹配以a结尾的字符串
好了,现在可以回过头来看看我们要处理的问题了。
我们要处理的是类似这样的,由用户输入的字符串,用户很可能会输入一些空格,所以最稳妥的办法是用一个字符串存下一整行的输入信息,然后从中删去所有的空格和制表符。
x^+x-3x^-
如何匹配这样复杂的表达式呢??首先还是得拆分,一点点入手。
我们可以把一个完整的多项式拆成若干项
x^
+x
-3x^-
先看看如何匹配其中的一项吧
很明显,最先出现的是表示正负的符号,但也可以不出现
[+-]? //匹配加号,减号,或不出现符号
然后就应该考虑匹配一个浮点数了,当然,如果系数为1,这个浮点数也可以不出现 所以最后可以用一个?表达可以不出现的意思。
[-]*\.?[-]+ //匹配一个浮点数
([-]*\.?[-]+)? //这个浮点数也可以不出现
然后考虑匹配指数位,当然,在指数为1的时候,也可以不出现,指数为0的时候,x也不用出现
\\^[+-]?[-]+ //匹配^1,^2,^3......
x(\\^[+-]?[-]+)? //匹配x^1,x^2,x^3...... 或者x (指数为1的情况)
(x(\\^[+-]?[-]+)?)? //允许匹配空串,用于指数为0的情况
好了,现在可以讲上述三个部分组合在一起了
[-+]?([-]*\.?[-]+)?(x(\\^[+-]?[-]+)?)? // 匹配 x^2,-3x^5,1,-x^-1......
还剩最后一点点就能完成了!!下面就是让这整个部分多次出现,用于匹配整个多项式,同时通过^匹配字符串的开头
^([-+]?([-]*\.?[-]+)?(x(\\^[+-]?[-]+)?)?)+$ //匹配整个多项式
emmmmm,好!如果你没有强迫症的话,大功告成了!
如果你有呢?
emmmmm,那就得再想想了。
在一个多项式中,符号,系数,指数不是必须全部出现的,但也不能全都不出现。反正一共只有23钟可能性,我们一样考虑一下就好了。(下面表格中星号代表这项出现)
| 符号 | 系数 | 指数 | 示例 | 是否可行 | 正则表达式 |
| * | * | * | -2x^2 | 是 |
[-+]([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9]+)?) |
| * | * | 2x^2 | 是 |
([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9]+)?) |
|
| * | * | -x^2 | 是 |
[-+](x(\\^[+-]?[0-9]+)?) |
|
| * | * | -2 | 是 |
[-+]([0-9]*\.?[0-9]+) |
|
| * | 否 | ||||
| * | 3 | 是 | ([0-9]*\.?[0-9]+) | ||
| * | x | 是 | (x(\\^[+-]?[0-9]+)?) | ||
| 否 |
发现有六种可行的情况,那就用笨办法依次匹配这六种情况呗。
然后把这六种打上括号,用 | 连接起来,就构成了修订后的用于匹配某一项的正则表达式。
([-+]([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9]+)?))|(([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9]+)?))|([-+](x(\\^[+-]?[0-9]+)?))|([-+]([0-9]*\.?[0-9]+))|(([0-9]*\.?[0-9]+))|((x(\\^[+-]?[0-9]+)?))
然后再像刚才一样 ,让这整个部分多次出现,用于匹配整个多项式,同时通过^匹配字符串的开头
^(([-+]([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9]+)?))|(([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9]+)?))|([-+](x(\\^[+-]?[0-9]+)?))|([-+]([0-9]*\.?[0-9]+))|(([0-9]*\.?[0-9]+))|((x(\\^[+-]?[0-9]+)?)))+$
接下来把代码实现方式摆出来,哦对了,要使用正则表达式的话,记得 #include <regex>
std::string poly = "x^2-x+3+x^-5";
std::string p1 = std::string("(") + "[-+]([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9])?)" + ")";
std::string p2 = std::string("(") + "([0-9]*\.?[0-9]+)(x(\\^[+-]?[0-9])?)" + ")";
std::string p3 = std::string("(") + "[-+](x(\\^[+-]?[0-9])?)" + ")";
std::string p4 = std::string("(") + "[-+]([0-9]*\.?[0-9]+)" + ")";
std::string p5 = std::string("(") + "([0-9]*\.?[0-9]+)" + ")";
std::string p6 = std::string("(") + "(x(\\^[+-]?[0-9])?)" + ")";
std::string p = p1 + "|" + p2 + "|" + p3 + "|" + p4 + "|" + p5 + "|" + p6;
std::string p_ = std::string("^(") + p + ")+$";
std::regex polyPattern(p_);
if(!std::regex_match(poly,polyPattern)){
std::cout<<"invalid polynomial!"<<std::endl;
}
下面我要做的,就是把每一项中的系数和指数识别出来,然后分别转换成double和int类型的变量便于计算。
std::regex cofPattern("^[-+]?([0-9]*\.?[0-9]+)"); //匹配系数
因为不能匹配 x, -x 这两种情况,所以在写代码的时候可以在适当判断一下
std::smatch cofResult;
double cof;
std::string term = "3x^5";
if( std::regex_search(term,cofResult,cofPattern) ){
const char* tempCof = cofResult.str().data(); //atof函数的参数是 const char* 类型的,我们需要转换一下
cof = std::atof(tempCof); // 将字符串转换成double类型数字
}else if(term[] == '-')
cof = -;
else
cof = ;
下面是最后一步!提取指数
std::regex expPattern1("x\\^[+-]?[0-9]+$"); // 匹配指数
但由于这样无法匹配指数为1的情况,所以我又写了个单独的正则表达式
std::regex expPattern2("x$"); // 匹配x在末尾
std::smatch expResult;
int exp;
if( std::regex_search(term,expResult,expPattern1) ){
const char* tempExp = expResult.str().substr().data();
exp = std::atoi(tempExp);
}else if(std::regex_search(term,expResult,expPattern2))
exp = ;
else
exp = ;
用正则表达式(regex)匹配多项式(polynomial)的更多相关文章
- C#正则表达式Regex常用匹配
使用Regex类需要引用命名空间:using System.Text.RegularExpressions; 利用Regex类实现验证 示例1:注释的代码所起的作用是相同的,不过一个是静态方法,一个是 ...
- C#正则表达式Regex类的用法
C#正则表达式Regex类的用法 更多2014/2/18 来源:C#学习浏览量:36891 学习标签: 正则表达式 Regex 本文导读:正则表达式的本质是使用一系列特殊字符模式,来表示某一类字符串, ...
- C#正则表达式Regex类
C#正则表达式Regex类的使用 C#中为正则表达式的使用提供了非常强大的功能,这就是Regex类.这个包包含于System.Text.RegularExpressions命名空间下面,而这个命名空间 ...
- 在C#中使用正则表达式自动匹配并获取所需要的数据
转自:http://my.oschina.net/bv10000/blog/111736 正则表达式能根据设置匹配各种数据(比如:e-mail地址,电话号码,身份中号码等等).正则表达式功能强大,使用 ...
- (四)boost库之正则表达式regex
(四)boost库之正则表达式regex 正则表达式可以为我们带来极大的方便,有了它,再也不用为此烦恼 头文件: #include <boost/regex.hpp> 1.完全匹配 std ...
- Java如何在正则表达式中匹配重复单词?
在Java编程中,如何在正则表达式中匹配重复单词? 以下示例显示了如何使用regex.Matcher类的p.matcher()方法和m.group()方法在正则表达式中搜索重复的单词. package ...
- 正则表达式—RegEx(RegularExpressio)(三)
今日随笔,继续写一点关于正则表达式的 知识.前两天介绍了正则表达式验证匹配,提取等一些基本的知识,今天继续分享下它的另一个强大的应用:替换(replace). 开始之前,还是要补一下昨天的内容. 在我 ...
- 正则表达式—RegEx(RegularExpressio)(二)
今日随笔,继续写一些关于正则表达式的东西. 首先补一点昨天的内容: 昨天少说了一个贪婪模式,什么是贪婪模式,比如像+或者*这样的元字符匹配中,会以最大匹配值匹配,这句话是什么意思呢,例如: 定义一个正 ...
- (转)正则表达式—RegEx(RegularExpressio)(三)
原文地址:http://www.cnblogs.com/feng-c-x/archive/2013/09/05/3302465.html 今日随笔,继续写一点关于正则表达式的 知识.前两天介绍了正则表 ...
- 正则表达式-Regex详解
1.什么是正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑.给定一个正 ...
随机推荐
- Oracle DBA 常用查询
1. 查询系统所有对象 select owner, object_name, object_type, created, last_ddl_time, timestamp, statusfrom db ...
- Redis “瘦身”指南
code[class*="language-"], pre[class*="language-"] { background-color: #fdfdfd; - ...
- PHP程序员40点陋习
1.不写注释 2.不使用可以提高生产效率的IDE工具 3.不使用版本控制 4.不按照编程规范写代码 5.不使用统一的方法 6.编码前不去思考和计划 7.在执行sql前不执行编码和安全检测 8.不使用测 ...
- JFrame的层次结构以及背景颜色设置问题
JFrame的层次结构: JFrame:窗体,也就是窗口的框架.默认为不可见.不透明的(可以使用isVisible和isOpaque来验证).创建窗口时,最后一步需要调用setVisible(true ...
- rem绝对自适应方案
rem css3新增的rem是现在非常受欢迎的单位.看一下MDN上的说明: 这个单位代表根元素的 font-size 大小(例如 <html> 元素的font-size). 使用这个单位可 ...
- 22.Linux-块设备驱动之框架详细分析(详解)
本节目的: 通过分析块设备驱动的框架,知道如何来写驱动 1.之前我们学的都是字符设备驱动,先来回忆一下 字符设备驱动: 当我们的应用层读写(read()/write())字符设备驱动时,是按字节/字符 ...
- Spring事务管理配置示例
(一).Spring事务特性 1.事务隔离级别 隔离级别是指若干个并发的事务之间的隔离程度. ISOLATION_DEFAULT:默认值,使用数据库的默认隔离级别,就是ISOLATION_READ_C ...
- c# 反射得到实体类的字段名称和值,DataTable转List<T>
/// <summary> /// 反射得到实体类的字段名称和值 /// var dict = GetProperties(model); /// </summary> /// ...
- 如何在Windows系统中配置Mysql群集(Mysql Cluster)
MySQL群集技术在分布式系统中为MySQL数据提供了冗余特性,增强了安全性,使得单个MySQL服务器故障不会对系统产生巨大的负面效应,系统的稳定性得到保障. Mysql群集(Cluster)简介 M ...
- ES6的变量解构赋值
前 言 ES6 解构赋值: ES6允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这被称为解构. 1.1 数组的结构赋值 1.1.1基本用法 JS中,为变量赋值直接指定.例如下面代码: ...