有什么手机流量突然消耗很快消‍耗比较少的体‍育直‍播客户‍端吗,打‍算看世+界‍杯直‍播用?

斐讯N1今日挖矿没流量,僧多粥少 - 斐讯版面(未经论坛许可请勿发布广告) -
恩山无线论坛 -
Powered by Discuz!
后使用快捷导航没有帐号?
只需一步,快速开始
请完成以下验证码
请完成以下验证码
查看: 2966|回复: 21
斐讯N1今日挖矿没流量,僧多粥少
僧多粥少,所以没流量。 我觉得大家还是不要抱太多希望。
感觉太失望了!
我的恩山、我的无线
The best wifi forum is right here.
&&必须上啊,才几天就能出多少啊
我的恩山、我的无线
The best wifi forum is right here.
关键是斐讯利用这流量来干啥。他要是开个下载器软件,估计流量就上去了
我的恩山、我的无线
The best wifi forum is right here.
请你们都关了,别和我抢矿,哈哈哈哈哈
我的恩山、我的无线
The best wifi forum is right here.
硬盘一直休眠。挖个卵
我的恩山、我的无线
The best wifi forum is right here.
先试探带宽,不急。
我的恩山、我的无线
The best wifi forum is right here.
你们都挖矿,我下车。
我的恩山、我的无线
The best wifi forum is right here.
为什么总是掉线?
我的恩山、我的无线
The best wifi forum is right here.
硬盘没反应的有多少?
我的恩山、我的无线
The best wifi forum is right here.
昨天开始,流量极其稳定。。。上下行都是惊人的3k
我的恩山、我的无线
The best wifi forum is right here.
斐讯的软件,呵呵,我笑了。
我的恩山、我的无线
The best wifi forum is right here.
硬盘灯都不亮,上行网速不跑,这在挖矿吗
我的恩山、我的无线
The best wifi forum is right here.
我没买呢?
我的恩山、我的无线
The best wifi forum is right here.
斐讯软件目测还没搞定,散了散了
我的恩山、我的无线
The best wifi forum is right here.
一天下来300兆,对了,也没看到硬盘有啥文件
我的恩山、我的无线
The best wifi forum is right here.
Powered byzwjkg.com的百度排名情况_站长工具_百度权重查询 - 爱站网
27 ~ 39 IP
35 ~ 41 IP
个相关子域名
百度权重调用代码
&a href="https://baidurank.aizhan.com/" target="_blank"&&img src="https://baidurank.aizhan.com/api/br?domain=zwjkg.com&style=images" /&&/a&
&a href="https://baidurank.aizhan.com/" target="_blank"&&script type="text/javascript" src="https://baidurank.aizhan.com/api/br?domain=zwjkg.com&style=text" charset="utf-8"&&/script&&/a&
&a href="https://baidurank.aizhan.com/" target="_blank"&&img src="https://baidurank.aizhan.com/api/mbr?domain=zwjkg.com&style=images" /&&/a&
&a href="https://baidurank.aizhan.com/" target="_blank"&&script type="text/javascript" src="https://baidurank.aizhan.com/api/mbr?domain=zwjkg.com&style=text" charset="utf-8"&&/script&&/a&
关闭关闭关闭zwj_506的专栏
https://blog.csdn.net/
https://static-blog.csdn.net/images/logo.gif
https://blog.csdn.net/zwj_506
https://blog.csdn.net/
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/
再谈如何将android studio项目转换成eclipse(转)
编辑推荐:,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!
更新:虽然本人坚守eclipse很久,但是现在我也不再推荐继续用eclispe了,自己的项目用还没什么问题,但是你如果想用github上的项目,用eclispe会越来越难。如果你仍然感兴趣,继续看下面的内容也没关系。
首先,不要因为编译原因而放弃。studio项目是完全可以转换成eclipse的
本站的开源代码板块有很多项目都是android studio开发的,很多同学以为必须要先学会studio,才能编译这些源代码,于是花了很长时间学studio,结果发现还是不会。其实任何studio项目都是可以转换成eclipse的,eclipse目前的编译能力比studio只会多不会少。只要你熟练了,一个中等复杂的studio项目转成eclipse也只是分分钟的事情。 在这里我要强调的是开源代码板块的studio项目95%以上都是我亲自编译成功并且运行了的,而剩下我没有验证的极少部分往往是因为该项目在github上已经得到非常多的star,而编译起来又异常复杂,但这是极少数的情况。
下面来谈谈studio到eclipse的转换问题。在studio项目转换成eclipse项目的过程中,对于studio的知识点只需记住条:studio项目中src/main目录下才是真正的项目代码,main下java目录里面的代码对应的是eclispe项目中的src目录中的代码。至于其他什么乱七八糟的Gradle 代码,完全不要去理会。
比如在 项目中在使用方法里面就有如下代码
repositories {
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
dependencies {
compile 'org.lucasr.twowayview:core:1.0.0-SNAPSHOT@aar'
compile 'org.lucasr.twowayview:layouts:1.0.0-SNAPSHOT@aar'}
看不懂?没关系,我也看不懂。你只要看懂上面红色文字部分的意思就行了。
首先要讲的就是项目结构的转换,这一点很基础,我已经在 一文中讲解过。
但是那篇文章没有结合具体的例子来说明,因此对于新手来讲,还是很难开头。其实除了项目的结构之外,项目的依赖关系其实也是一个难点:对于一个studio项目我们如何知道他依赖了哪些东西呢?
一个比较典型的实例
一般来讲一个项目如果没有什么新系统的特征,直接转换成eclipse的目录结构然后eclipse import进去就ok了,但是现在很多项目往往使用了Material Design中的一些东西,比如ToolBar,RecyclerView以及appcompat的主题等,这种依赖关系就比较复杂。
下面我以 为例讲解如何将它转换成eclipse项目。
更改项目结构
首先下载然后解压:
这么复杂!吓到了是吧,没关系很多文件和目录我可以直接删掉,从文件的名称来看example下面应该是demo代码,library下面是库代码。其他的直接删掉,当然为了保险起见,你还是点击去看下如果里面有src目录基本上就可以确认这是跟项目代码相关的了。删掉其他文件和目录之后我们就只剩下:
心情顿时就好了。
我们先来解决library目录中的问题。打开library
回想上面说的studio项目中src/main目录下才是真正的项目代码。因此我们将src/main中的文件全部copy出来,其他的都可以直接删掉了,至于copy出来放在哪里那是你的事,一般我自己的做法是直接放在library目录下,然后删除掉copy文件之外的所有东西。如果你按照我描述的做,那么到这一步library下面应该是这样的:
再回想上面说的main下java目录里面的代码对应的是eclispe项目中的src目录中的代码。因此我们将java目录改名src目录:
这不就是熟悉的eclipse项目么,其实非常简单,本来我是不想写那么多的,但是有些人就是不会。至此library目录中的项目结构我们就改造完成了。
按照完全一致的方法我们去改造example目录。
导入eclipse
将修正过的项目(此处为SuperSLiM-master目录)下的所有内容导入到eclipse中:
导入之后生成了library和MainActivity两个project:
library是库,而MainActivity中是demo,通常我喜欢将他们的项目名称改成github上的名称,这里我分别更改为:SuperSLiMLibrary和SuperSLiMDemo
从上图中可以看到导入的两个project有错误,其实这些错误基本上是依赖关系导致的。因为SuperSLiMDemo是依赖于SuperSLiMLibrary的,所以我们先从SuperSLiMLibrary中的错误入手。
在这个时候我并不知道这些错误具体产生的原因,所以我需要查看具体的错误文件,打开项目的包,发现以下java文件有红叉:
随便选择一个文件进去看看,这里我就选择第一个好了找到了第一个错误:
LayoutState的recyclerState方法找不到,LayoutState不就是上图中的第三个文件么,进去很多错误,随便截个图
显然是需要导入RecyclerView包了。期望导入RecyclerView之后就不会有任何问题了。
导入后发现大部分错误不见了,只有LayoutState还有错误,原来是因为LayoutState中有这样的代码
if (Build.VERSION.SDK_INT & Build.VERSION_CODES.LOLLIPOP) {
这要求编译环境是5.0才行。将sdk换成5.0的,ok了,SuperSLiMLibrary已经没有任何错误了。
看到这里你可能会想,是不是麻烦了点,确实,事实上我并不是上面的每一步都按部就班,我一般先在每个错误文件中扫描以便错误的地方,很快就可以定位到RecyclerView,然后添加依赖,甚至我都不想去扫描错误直接添加RecyclerView的依赖,因为github中已经说了这个项目是RecyclerView实现的。
SuperSLiMLibrary到这里还有最后一步,将它设置成library,不然SuperSLiMDemo在添加lib的时候是找不到他的。
再来看看SuperSLiMDemo中的错误。
在这之前我首先将刚刚的SuperSLiMLibrary添加到依赖中。然后还是有这些错误:
style中的错误是因为没有依赖appcompat,于是先添加了再说,一定要添加最新版本的appcompat(兼容5.0的appcompat),为什么呢,因为在主题代码中有下面这些属性:
name="AppTheme.Base" parent="Theme.AppCompat.Light"
name="colorPrimary"@color/primary
name="colorPrimaryDark"@color/primary_dark
name="colorAccent"@color/accent
name="android:windowNoTitle"true
name="windowActionBar"false
当你看到colorPrimary属性的时候肯定需要在appcompat中编译的。
同时因为SuperSLiMLibrary都是在5.0上编译的,因此SuperSLiMDemo我也同样在5.0上编译。
然后你会发现我都没去看src中的java代码,就完全没有错误了。
至此SuperSLiM这个项目就完全转换成eclipse版本的项目了。
SuperSLiM不是最好转换的项目,也不是最难转换的项目,这篇文章只是告诉你,studio转eclipse是可行的,遇到问题该怎么解决。文中所描述的步骤完全没必要一一照搬,因为根本就没有什么固定的步骤。
另外我看到有网友对使用了appcompat的项目比较排斥,看到使用了appcompat就不研究了,这是完全错误的思想,现在绝大多数开源项目都用了appcompat,而且因为5.0的出现appcompat还将被越来越多的项目使用,你可以看到在android官方文档上面,5.0的很多新特性更多的是介绍如何用appcompat去实现,而不是标准的sdk中的类。
原文来自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/94.html
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/
作为一个C++面试者,面试时难免少不了各种算法题,本人一边面试一边总结,把自己面到的算法题总结如下,希望自己能得到提升,也希望能帮助到一些面试者,有更好方法的希望能提出来供大家讨论:
给定无序自然数数组,求最大连续自然数个数,时间复杂度为O(n)(阿里面试)
例如:[100,3,1,2]输出应该为3,最长连续自然数序列为:1,2,3 求解.[4,7,5,9,8]连续的串就是3,【1,100,5,4,2,3】是4,【7
3 2 4 6 5】答案是6
答案思路:
维持两个hash表tables:
Start表,其中的条目都是如下格式(start-point,length),包含的某个连续序列起始数以及序列长度。
End表,其中的条目都是如下格式(end-point,length),包含的某个连续序列结束数以及序列长度。
扫描原始数组,做如下操作: 对于当前值value,
判断value + 1是否存在于start表中。
如果存在,删除相应的条目,创建一个新条目(value,length + 1),同时更新end表相应条目,结束数不变,该对应长度加一。
判断value - 1是否存在于end表中。 如果存在,删除相应的条目,创建一个新条目(value,length + 1),同时更新start表相应条目,开始数不表,该对应长度加一。 如果在两个表中都存在,则合并两个已经存在的连续序列为一个。将四个条目删除,新建两个条目,每两个条目代表一个连续序列。 如果都不存在,则只需要在两个表中创建一个新的长度为1的条目。 一直这样等到数组中所有元素处理完毕,然后扫描start表寻找length值最大的那个即可。 这里要达到O(n)时间复杂度,start表和end表都用hash表实现,而且必须满足相关操作查找/添加/删除能够在O(1)时间复杂度内完成。
实例分析:
int[] input = {10,21,45,22,7,2,67,19,13,45,12, 11,18,16,17,100,201,20,101};
初始化状态:
Start table:{}
End table:{}
开始遍历数组:
10:两个数组中都不存在,添加条目。
Start table:{(10,1)}
End table:{(10,1)}
21:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,1)}
End table:{(10,1),(21,1)}
45:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,1),(45,1)}
End table:{(10,1),(21,1),(45,1)}
22:22-1=21存在于end表中需要进行更新。
Start table:{(10,1),(21,2),(45,1)}
End table:{(10,1),(22,2),(45,1)}
7:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,2),(45,1),(7,1)}
End table:{(10,1),(22,2),(45,1),(7,1)}
2:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,2),(45,1),(7,1),(2,1)}
End table:{(10,1),(22,2),(45,1),(7,1),(2,1)}
67:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,2),(45,1),(7,1),(2,1),(67,1)}
End table:{(10,1),(22,2),(45,1),(7,1),(2,1),(67,1)}
19:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,2),(45,1),(7,1),(2,1),(67,1),(19,1)}
End table:{(10,1),(22,2),(45,1),(7,1),(2,1),(67,1),(19,1)}
13:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,2),(45,1),(7,1),(2,1),(67,1),(19,1),(13,1)}
End table:{(10,1),(22,2),(45,1),(7,1),(2,1),(67,1),(19,1),(13,1)}
45:两个数组中都不存在,添加条目。
Start table:{(10,1),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,1),(13,1)}
End table:{(10,1),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,1),(13,1)}
12:12+1=13存在start表中,更新。
Start table:{(10,1),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,1),(12,2)}
End table:{(10,1),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,1),(13,2)}
11:11+1=12都存在,合并。
Start table:{(10,4),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,1)}
End table:{(13,4),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,1)}
18:18+1=19存在start表中,更新。
Start table:{(10,4),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(18,2)}
End table:{(13,4),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,2)}
16:都不存在,添加条目。
Start table:{(10,4),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(18,2),(16,1)}
End table:{(13,4),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,2),(16,1)}
17:都存在,合并。
Start table:{(10,4),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(16,4)}
End table:{(13,4),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,4)}
100:都不存在,添加条目。
Start table:{(10,4),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(16,4),(100,1)}
End table:{(13,4),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,4),(100,1)}
201:都不存在,添加条目。
Start table:{(10,4),(21,2),(45,1),(45,1),(7,1),(2,1),(67,1),(16,4),(100,1),(201,1)}
End table:{(13,4),(22,2),(45,1),(45,1),(7,1),(2,1),(67,1),(19,4),(100,1),(201,1)}
20:都存在,合并。
Start table:{(10,4),(16,7),(45,1),(45,1),(7,1),(2,1),(67,1),(100,1),(201,1)}
End table:{(13,4),(22,7),(45,1),(45,1),(7,1),(2,1),(67,1),(100,1),(201,1)}
101:都存在,合并。
Start table:{(10,4),(16,7),(45,1),(45,1),(7,1),(2,1),(67,1),(100,1),(201,1),(101,1)}
End table:{(13,4),(22,7),(45,1),(45,1),(7,1),(2,1),(67,1),(100,1),(201,1),(201,1)}
最后搜索start表,找到length值最大的,为7.连续自然数序列是:(16,17,18,19,20,21,22). 结束。
设计个数据结构,方便的插入删除一个数并能方便的找出中位数(阿里面试)
假如有一需求是这样的,它会较频繁的动态向数列中插入或删除数据,且又需要随时获取到数列的中位数,该如何设计数据结构和算法。
先说下,中位数的定义:如下:
所谓的是中位数是指:将数据按大小顺序排列起来,形成一个数列,居于数列中间位置的数叫中位数,且要分奇数与偶数两种情况来分析。
1:如果总数个数是奇数,按从小到大的顺序,取中间的那个数
2:如果总数个数是偶数,按从小到大的顺序,取中间那两个数的平均数
例:数列:1、9、11中位数:9,而数列:1、9、11、39,则是(9+11)/2 = 10
答题思路:
思考过程1:
由于中位数是位于中间位置,所以容易想到的思路就是,设计一种以中位数隔开,维护左右两边的数列,左边都是小于中位数的,右边都是大于中位数的数据结构
思考过程2:
如何建立左右两边的数据结构,才能易于与中位数比较,又易于插入删除。
显然,中位数的计算方式是,若数列为偶数,是左边的最大值和右边的最小值除2;若不是,也要维护这左右的最大值和右边的最大值,原因是,经常插入或删除,数据的总数,时常在奇数和偶数之间变换。
所以,对于左边的数列,我们试图是设计出容易找到最小值的数据结构,同理,右边也一样,所以自然而然,就想到堆。即大顶堆和小顶堆。
得出简单结论:可以利用大堆和小堆来解决这个问题,大致过程如下:
1:用一个大顶堆存储数列中不大于中位数的元素
2:用一个小顶堆存储数列中不小于中位数的元素
显然,这种方式读取中位数的时间复杂度为O(1),插入和删除元素(包括调整堆)的时间复杂度为:O(logN)。
这道题的解决得益于求数组中连续元素的最大和的方法,那个问题剑指offer中有,不会做的可以自己去看。我的理解就是要想得到差值的最大值,那么肯定是要求当前值减去这个指前面的最小值,我们可以不停地更新这个差值和最小值,然后去遍历完一遍就可以了。这样就能做到遍历整个数组的时候,问题就解决了。达到了最快的速度O(N)
美团笔试题
给定一个凸四边形,如何判断一个点在这个凸四边形内还是外?
如果一个点在这个凸四边形内,那么按照逆时针方向走的话,该点一定会在每一条的左边。
所以方法就是:按照逆时针方向遍历这个凸四边形的每一条边的两个顶点A(X1,Y1)和B(X2,Y2),然后判断给定点是否在AB矢量左边就可以了。
而判断一个点是否在一个矢量的左边,可以利用矢量叉积。
设A(x1,y1),B(x2,y2),给定点是C(x3,y3),构造两条矢量边:
AB=(x2-x1,y2-y1), AC=(x3-x1,y3-y1)
则AB和AC的叉积为(2*2的行列式):
|x2-x1, y2-y1|
|x3-x1, y3-y1|
值为:r = (x2-x1)(y3-y1) - (y2-y1)(x3-x1)
然后利用右手法则进行判断:
如果r & 0,则点C在矢量AB的左边
如果r & 0,则点C在矢量AB的右边
这样就可以判断点C与AB的相对位置了。然后按照逆时针方向,对凸四边形的每一条边都如此判断,如果每次都判断出C在左边,那么就说明这个点在凸多边形内部了。
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/
有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有宏的情况下):
原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
原则2、作为成员:如果一个结构里有某些成员,则成员要从其内部最素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)
原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。
例1:struct {
sizeof(A) = 6; 这个很好理解,三个short都为2。
sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。
例2:struct A{
sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。
sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。
深究一下,为什么是这样,我们可以看看内存里的布局情况。
A的内存布局:1111, 1*, 11
B的内存布局:1***, 1111, 11**
其中星号*表示填充的字节。A中,b后面为何要补充一个字节?因为c为short,其起始位置要为2的倍数,就是原则1。c的后面没有补充,因为b和c正好占用4个字节,整个A占用空间为4的倍数,也就是最大成员int类型的倍数,所以不用补充。
B中,b是char为1,b后面补充了3个字节,因为a是int为4,根据原则1,起始位置要为4的倍数,所以b后面要补充3个字节。c后面补充两个字节,根据原则3,整个B占用空间要为4的倍数,c后面不补充,整个B的空间为10,不符,所以要补充2个字节。
再看一个结构中含有结构成员的例子:
例3:struct A{
char e[2];
sizeof(A) = 24; 这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。
sizeof(B) = 48; 看看B的内存布局。
B的内存布局:11* *, 11, 11 * * * * * *, 1111* * * *, 11 * * * *
i其实就是A的内存布局。i的起始位置要为8的倍数,所以h后面要补齐。把B的内存布局弄清楚,有关结构体的对齐方式基本就算掌握了。
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/
函数后面加const
类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变。
在设计类的时候,一个原则就是对于不改变数据成员的成员函数都要在后面加 const,而对于改变数据成员的成员函数不能加 const。所以 const 关键字对成员函数的行为作了更加明确的限定:有 const 修饰的成员函数(指 const 放在函数参数表的后面,而不是在函数前面或者参数表内),只能读取数据成员,不能改变数据成员;没有 const 修饰的成员函数,对数据成员则是可读可写的。 除此之外,在类的成员函数后面加 const 还有什么好处呢?楼主告诉我们的:“获得能力:可以操作常量对象”,其实应该是常量(即 const)对象可以调用 const 成员函数,而不能调用非const修饰的函数。正如非const类型的数据可以给const类型的变量赋值一样,反之则不成立。 对于const成员函数,"不能修改类的数据成员,不能在函数中调用其他不是const的函数",这是由const的属性决定的,楼主说得完全正确。 请看下面一个完整的例子,然后我再作一些说明。 #include &iostream&;
#include &string&;
class Student {
Student() {}
Student( const string& nm, int sc = 0 )
: name( nm ), score( sc ) {}
void set_student( const string& nm, int sc = 0 )
const string& get_name() const
int get_score() const
// output student's name and score
void output_student( const Student& student )
cout && student.get_name() && "\t";
cout && student.get_score() &&
int main()
Student stu( "Wang", 85 );
output_student( stu );
设计了一个类 Student,数据成员有 name 和 score,有两个构造函数,有一个设置成员数据函数 set_student(),各有一个取得 name 和 score 的函数 get_name() 和 get_score()。请注意 get_name() 和 get_score() 后面都加了 const,而 set_student() 后面没有(也不能有const)。 首先说一点题外话,为什么 get_name() 前面也加 const。如果没有前后两个 const 的话,get_name() 返回的是对私有数据成员 name 的引用,所以通过这个引用可以改变私有成员 name 的值,如
Student stu( "Wang", 85 );
stu.get_name() = "Li";
即把 name 由原来的 "Wang" 变成了 "Li",而这不是我们希望的发生的。所以在 get_name() 前面加 const 避免这种情况的发生。 那么,get_name() 和 get_score() 这两个后面应该加 const的成员函数,如果没有 const 修饰的话可不可以呢?回答是可以!但是这样做的代价是:const对象将不能再调用这两个非const成员函数了。如 const string& get_name(); // 这两个函数都应该设成 const 型
int get_score();
void output_student( const Student& student )
cout && student.get_name() && "\t"; // 如果 get_name() 和 get_score() 是非const成员函数,这一句和下一句调用是错误的
cout && student.get_score() &&
由于参数student表示的是一个对const Student型对象的引用,所以 student 不能调用非const成员函数如 set_student()。如果 get_name() 和 get_score() 成员函数也变成非const型,那么上面的 student.get_name() 和 student.get_score() 的使用就是非法的,这样就会给我们处理问题造成困难。 因此,我们没有理由反对使用const,该加const时就应该加上const,这样使成员函数除了非const的对象之外,const对象也能够调用它。
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/
https://blog.csdn.net/zwj_506/article/details/9703301
https://blog.csdn.net/zwj_506/article/details/9703301
 什么是HTTP协议
  协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器
  目前我们使用的是HTTP/1.1 版本
  Web服务器,浏览器,代理服务器
  当我们打开浏览器,在地址栏中输入URL,然后我们就看到了网页。 原理是怎样的呢?
  实际上我们输入URL后,我们的浏览器给Web服务器发送了一个Request, Web服务器接到Request后进行处理,生成相应的Response,然后发送给浏览器, 浏览器解析Response中的HTML,这样我们就看到了网页,过程如下图所示
  我们的Request 有可能是经过了代理服务器,最后才到达Web服务器的。
  过程如下图所示
  代理服务器就是网络信息的中转站,有什么功能呢?
  1. 提高访问速度, 大多数的代理服务器都有缓存功能。
  2. 突破限制, 也就是翻墙了
  3. 隐藏身份。
  URL详解
  URL(Uniform Resource Locator) 地址用于描述一个网络上的资源,
基本格式如下
schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]
  scheme
指定低层使用的协议(例如:http, https, ftp)
HTTP服务器的IP地址或者域名
HTTP服务器的默认端口是80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如 http://www.cnblogs.com:8080/
访问资源的路径
  url-params
  query-string
发送给http服务器的数据
  anchor-
  URL 的一个例子
http://www.mywebsite.com/sj/id=8079?name=sviergn&x=true#stuff
Schema: http
host: www.mywebsite.com
path: /sj/test
URL params: id=8079
Query String: name=sviergn&x=true
Anchor: stuff
  HTTP协议是无状态的
  http协议是无状态的,同一个客户端的这次请求和上次请求是没有对应关系,对http服务器来说,它并不知道这两个请求来自同一个客户端。 为了解决这个问题, Web程序引入了Cookie机制来维护状态.
  HTTP消息的结构
  先看Request 消息的结构,
Request 消息分为3部分,第一部分叫请求行, 第二部分叫http header, 第三部分是body. header和body之间有个空行, 结构如下图
  第一行中的Method表示请求方法,比如"POST","GET",
Path-to-resoure表示请求的资源, Http/version-number 表示HTTP协议的版本号
  当使用的是"GET" 方法的时候, body是为空的
  比如我们打开博客园首页的request 如下
GET http://www.cnblogs.com/ HTTP/1.1
Host: www.cnblogs.com
  我们用Fiddler 捕捉一个博客园登录的Request 然后分析下它的结构, 在Inspectors tab下以Raw的方式可以看到完整的Request的消息,
  我们再看Response消息的结构, 和Request消息的结构基本一样。 同样也分为三部分,第一部分叫request line, 第二部分叫request header,第三部分是body. header和body之间也有个空行,
结构如下图
  HTTP/version-number表示HTTP协议的版本号,
status-code 和message 请看下节[]的详细解释.
  我们用Fiddler 捕捉一个博客园首页的Response然后分析下它的结构, 在Inspectors tab下以Raw的方式可以看到完整的Response的消息,
  Get和Post方法的区别
  Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,删4个操作。 我们最常见的就是GET和POST了。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息.
  我们看看GET和POST的区别
  1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456.
POST方法是把提交的数据放在HTTP包的Body中.
  2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
  3. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。
  4. GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.
  状态码
  Response 消息中的第一行叫做状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。
  状态码用来告诉HTTP客户端,HTTP服务器是否产生了预期的Response.
  HTTP/1.1中定义了5类状态码, 状态码由三位数字组成,第一个数字定义了响应的类别
提示信息 - 表示请求已被成功接收,继续处理
成功 - 表示请求已被成功接收,理解,接受
重定向 - 要完成请求必须进行更进一步的处理
客户端错误 -
请求有语法错误或请求无法实现
服务器端错误 -
服务器未能实现合法的请求
  看看一些常见的状态码
  200 OK
  最常见的就是成功响应状态码200了, 这表明该请求被成功地完成,所请求的资源发送回客户端
  如下图, 打开博客园首页
  302 Found
  重定向,新的URL会在response中的Location中返回,浏览器将会使用新的URL发出新的Request。
  例如在IE中输入http://www.google.com. HTTP服务器会返回304, IE取到Response中Location header的新URL, 又重新发送了一个Request.
  304 Not Modified
  代表上次的文档已经被缓存了, 还可以继续使用,
  例如打开博客园首页, 发现很多 Response 的status code 都是304
  提示: 如果你不想使用本地缓存可以用Ctrl+F5强制刷新页面
  400 Bad Request
客户端请求与语法错误,不能被服务器所理解
  403 Forbidden 服务器收到请求,但是拒绝提供服务
  404 Not Found
  请求资源不存在(输错了URL)
  比如在IE中输入一个错误的URL, http://www.cnblogs.com/tesdf.aspx
  500 Internal Server Error 服务器发生了不可预期的错误
  503 Server Unavailable 服务器当前不能处理客户端的请求,一段时间后可能恢复正常
  HTTP Request header
  使用Fiddler 能很方便的查看Reques header, 点击Inspectors tab -& Request tab -& headers
如下图所示.
  header 有很多,比较难以记忆,我们也按照Fiddler那样把header 进行分类,这样比较清晰也容易记忆。
  Cache 头域
  If-Modified-Since
  作用: 把浏览器端缓存页面的最后修改时间发送到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行对比。如果时间一致,那么返回304,客户端就直接使用本地缓存文件。如果时间不一致,就会返回200和新的文件内容。客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示在浏览器中。
  例如:If-Modified-Since: Thu, 09 Feb :57 GMT
  实例如下图
  If-None-Match
  作用: If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息。 当用户再次请求该资源时,将在HTTP Request 中加入If-None-Match信息(ETag的值)。如果服务器验证资源的ETag没有改变(该资源没有更新),将返回一个304状态告诉客户端使用本地缓存文件。否则将返回200状态和新的资源和Etag.
使用这样的机制将提高网站的性能
  例如: If-None-Match: "03f2b33c0bfcc1:0"
  实例如下图
  Pragma
  作用: 防止页面被缓存, 在HTTP/1.1版本中,它和Cache-Control:no-cache作用一模一样
  Pargma只有一个用法, 例如: Pragma: no-cache
  注意: 在HTTP/1.0版本中,只实现了Pragema:no-cache, 没有实现Cache-Control
  Cache-Control
  作用: 这个是非常重要的规则。 这个用来指定Response-Request遵循的缓存机制。各个指令含义如下
  Cache-Control:Public
可以被任何缓存所缓存()
  Cache-Control:Private
内容只缓存到私有缓存中
  Cache-Control:no-cache
所有内容都不会被缓存
  还有其他的一些用法, 我没搞懂其中的意思, 请大家参考其他的资料
  Client 头域
  Accept
  作用: 浏览器端可以接受的媒体类型,
  例如:
Accept: text/html
代表浏览器可以接受服务器回发的类型为 text/html
也就是我们常说的html文档,
  如果服务器无法返回text/html类型的数据,服务器应该返回一个406错误(non acceptable)
  通配符 * 代表任意类型
Accept: */*
代表浏览器可以处理所有类型,(一般浏览器发给服务器都是发这个)
  Accept-Encoding:
  作用: 浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate),(注意:这不是只字符编码);
  例如: Accept-Encoding: gzip, deflate
  Accept-Language
  作用: 浏览器申明自己接收的语言。
  语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等;
  例如: Accept-Language: en-us
  User-Agent
  作用:告诉HTTP服务器, 客户端使用的操作系统和浏览器的名称和版本.
  我们上网登陆论坛的时候,往往会看到一些欢迎信息,其中列出了你的操作系统的名称和版本,你所使用的浏览器的名称和版本,这往往让很多人感到很神奇,实际上,服务器应用程序就是从User-Agent这个请求报头域中获取到这些信息User-Agent请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器。
  例如: User-Agent: Mozilla/4.0 ( MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727; .NET CLR 3.0.; .NET CLR 3.5.30729; .NET4.0C; InfoPath.2; .NET4.0E)
  Accept-Charset
  作用:浏览器申明自己接收的字符集,这就是本文前面介绍的各种字符集和字符编码,如gb2312,utf-8(通常我们说Charset包括了相应的字符编码方案);
  例如:
  Cookie/Login 头域
  Cookie:
  作用: 最重要的header, 将cookie的值发送给HTTP 服务器
  Entity头域
  Content-Length
  作用:发送给HTTP服务器数据的长度。
  例如: Content-Length: 38
  Content-Type
  作用:
  例如:Content-Type: application/x-www-form-urlencoded
  Miscellaneous 头域
  Referer:
  作用: 提供了Request的上下文信息的服务器,告诉服务器我是从哪个链接过来的,比如从我主页上链接到一个朋友那里,他的服务器就能够从HTTP Referer中统计出每天有多少用户点击我主页上的链接访问他的网站。
  例如: Referer:http://translate.google.cn/?hl=zh-cn&tab=wT
  Transport 头域
  Connection
  例如: Connection: keep-alive
当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接
  例如:
Connection: close
代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭, 当客户端再次发送Request,需要重新建立TCP连接。
  Host(发送请求时,该报头域是必需的)
  作用: 请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的
  例如: 我们在浏览器中输入:http://www.guet.edu.cn/index.html
  浏览器发送的请求消息中,就会包含Host请求报头域,如下:
  Host:http://www.guet.edu.cn
  此处使用缺省端口号80,若指定了端口号,则变成:Host:指定端口号
HTTP Response header
  同样使用Fiddler 查看Response header, 点击Inspectors tab -&Response tab-& headers
如下图所示
  我们也按照Fiddler那样把header 进行分类,这样比较清晰也容易记忆。
  Cache头域
生成消息的具体时间和日期
  例如: Date: Sat, 11 Feb :14 GMT
  Expires
  作用: 浏览器会在指定过期时间内使用本地缓存
  例如: Expires: Tue, 08 Feb :14 GMT
  作用:
  例如: Vary: Accept-Encoding
  Cookie/Login 头域
  作用: 用于跨域设置Cookie, 这样可以解决iframe跨域访问cookie的问题
  例如: P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR
  Set-Cookie
  作用: 非常重要的header, 用于把cookie 发送到客户端浏览器, 每一个写入cookie都会生成一个Set-Cookie.
  例如: Set-Cookie: sc=4c31523a; path=/; domain=.acookie.taobao.com
  Entity头域
和If-None-Match 配合使用。 (实例请看上节中If-None-Match的实例)
  例如: ETag: "03f2b33c0bfcc1:0"
  Last-Modified:
  作用: 用于指示资源的最后修改日期和时间。(实例请看上节的If-Modified-Since的实例)
  例如: Last-Modified: Wed, 21 Dec :10 GMT
  Content-Type
  作用:WEB服务器告诉浏览器自己响应的对象的类型和字符集,
  Content-Type: text/ charset=utf-8
  Content-Type:text/charset=GB2312
  Content-Type: image/jpeg
  Content-Length
  指明实体正文的长度,以字节方式存储的十进制数字来表示。在数据下行的过程中,Content-Length的方式要预先在服务器中缓存所有数据,然后所有数据再一股脑儿地发给客户端。
  例如: Content-Length: 19847
  Content-Encoding
  WEB服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。
  例如:Content-Encoding:gzip
  Content-Language
  作用: WEB服务器告诉浏览器自己响应的对象的语言者
  例如: Content-Language:da
  Miscellaneous 头域
  Server:
  作用:指明HTTP服务器的软件信息
  例如:Server: Microsoft-IIS/7.5
  X-AspNet-Version:
  作用:如果网站是用ASP.NET开发的,这个header用来表示ASP.NET的版本
  例如: X-AspNet-Version: 4.0.30319
  X-Powered-By:
  作用:表示网站是用什么技术开发的
  例如: X-Powered-By: ASP.NET
  Transport头域
  Connection
  例如: Connection: keep-alive
当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接
  例如:
Connection: close
代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭, 当客户端再次发送Request,需要重新建立TCP连接。
  Location头域
  Location
  作用: 用于重定向一个新的位置, 包含新的URL地址
  实例请看304状态实例
  HTTP协议是无状态的和Connection: keep-alive的区别
  无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。从另一方面讲,打开一个服务器上的网页和你之前打开这个服务器上的网页之间没有任何联系。
  HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议(无连接)。
  从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。
  Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/9703301
https://blog.csdn.net/zwj_506/article/details/9701201
https://blog.csdn.net/zwj_506/article/details/9701201
来园子之前写的一篇,部分翻译自codeproject的。
由于评论里有过长的URL,所以本页排版比较混乱,推荐你,看完了如果有问题,再到这里来提出.
一些要说的话:
如果你没有正则表达式的基础,请跟着教程“一步步来”。请不要大概地扫两眼就说看不懂——以这种态度我写成什么样你也看不懂。当我告诉你这是“30分钟入门教程”时,请不要试图在30秒内入门。
事实是,我身边有个才接触电脑,对操作都不是很熟练的人通过自己学习这篇教程,最后都能在文章采集系统中使用正则表达式完成任务。而且,他写的表达式中,还使用了“零宽断言”等“高级”技术。
所以,如果你能具体地说明你的问题,我很愿意帮助你。但是如果你概括地说看不懂,那不是我的问题。欢迎转载,但请声明作者以及来源。正则表达式30分钟入门教程
版本:v2.31 () 作者: 转载请注明
30分钟内让你明白正则表达式是什么,并对它有一些基本的了解,让你可以在自己的程序或网页里使用它。
如何使用本教程
最重要的是——请给我30分钟,如果你没有使用正则表达式的经验,请不要试图在30秒内入门——除非你是超人 :)
别被下面那些复杂的表达式吓倒,只要跟着我一步一步来,你会发现正则表达式其实并没有你想像中的那么困难。当然,如果你看完了这篇教程之后,发现自己明白了很多,却又几乎什么都记不得,那也是很正常的——我认为,没接触过正则表达式的人在看完这篇教程后,能把提到过的语法记住80%以上的可能性为零。这里只是让你明白基本的原理,以后你还需要多练习,多使用,才能熟练掌握正则表达式。
除了作为入门教程之外,本文还试图成为可以在日常工作中使用的正则表达式语法参考手册。就作者本人的经历来说,这个目标还是完成得不错的——你看,我自己也没能把所有的东西记下来,不是吗?
文本格式约定:专业术语 元字符/语法格式 正则表达式 正则表达式中的一部分(用于分析) 对其进行匹配的源字符串 对正则表达式或其中一部分的说明
本文右边有一些注释,主要是用来提供一些相关信息,或者给没有程序员背景的读者解释一些基本概念,通常可以忽略。
正则表达式到底是什么东西?
字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等等。字符串是0个或更多个字符的序列。文本也就是文字,字符串。说某个字符串匹配某个正则表达式,通常是指这个字符串里有一部分(或几部分分别)能满足表达式给出的条件。
在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
很可能你使用过Windows/Dos下用于文件查找的通配符(wildcard),也就是*和?。如果你想查找某个目录下的所有的Word文档的话,你会搜索*.doc。在这里,*会被解释成任意的字符串。和通配符类似,正则表达式也是用来进行文本匹配的工具,只不过比起通配符,它能更精确地描述你的需求——当然,代价就是更复杂——比如你可以编写一个正则表达式,用来查找所有以0开头,后面跟着2-3个数字,然后是一个连字号“-”,最后是7或8位数字的字符串(像010-或)。
学习正则表达式的最好方法是从例子开始,理解例子之后再自己对例子进行修改,实验。下面给出了不少简单的例子,并对它们作了详细的说明。
假设你在一篇英文小说里查找hi,你可以使用正则表达式hi。
这几乎是最简单的正则表达式了,它可以精确匹配这样的字符串:由两个字符组成,前一个字符是h,后一个是i。通常,处理正则表达式的工具会提供一个忽略大小写的选项,如果选中了这个选项,它可以匹配hi,HI,Hi,hI这四种情况中的任意一种。
不幸的是,很多单词里包含hi这两个连续的字符,比如him,history,high等等。用hi来查找的话,这里边的hi也会被找出来。如果要精确地查找hi这个单词的话,我们应该使用\bhi\b。
\b是正则表达式规定的一个特殊代码(好吧,某些人叫它元字符,metacharacter),代表着单词的开头或结尾,也就是单词的分界处。虽然通常英文的单词是由空格,标点符号或者换行来分隔的,但是\b并不匹配这些单词分隔字符中的任何一个,它只匹配一个位置。
如果需要更精确的说法,\b匹配这样的位置:它的前一个字符和后一个字符不全是(一个是,一个不是或不存在)\w。
假如你要找的是hi后面不远处跟着一个Lucy,你应该用\bhi\b.*\bLucy\b。
这里,.是另一个元字符,匹配除了换行符以外的任意字符。*同样是元字符,不过它代表的不是字符,也不是位置,而是数量——它指定*前边的内容可以连续重复使用任意次以使整个表达式得到匹配。因此,.*连在一起就意味着任意数量的不包含换行的字符。现在\bhi\b.*\bLucy\b的意思就很明显了:先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词。
换行符就是'\n',ASCII编码为10(十六进制0x0A)的字符。
如果同时使用其它元字符,我们就能构造出功能更强大的正则表达式。比如下面这个例子:
0\d\d-\d\d\d\d\d\d\d\d匹配这样的字符串:以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字(也就是中国的电话号码。当然,这个例子只能匹配区号为3位的情形)。
这里的\d是个新的元字符,匹配一位数字(0,或1,或2,或……)。-不是元字符,只匹配它本身——连字符(或者减号,或者中横线,或者随你怎么称呼它)。
为了避免那么多烦人的重复,我们也可以这样写这个表达式:0\d{2}-\d{8}。 这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)。
测试正则表达式
其它可用的测试工具:
如果你不觉得正则表达式很难读写的话,要么你是一个天才,要么,你不是地球人。正则表达式的语法很令人头疼,即使对经常使用它的人来说也是如此。由于难于读写,容易出错,所以找一种工具对正则表达式进行测试是很有必要的。
不同的环境下正则表达式的一些细节是不相同的,本教程介绍的是微软 .Net Framework 4.0 下正则表达式的行为,所以,我向你推荐我编写的.Net下的工具 。请参考该页面的说明来安装和运行该软件。
下面是Regex Tester运行时的截图:
现在你已经知道几个很有用的元字符了,如\b,.,*,还有\d.正则表达式里还有更多的元字符,比如\s匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等。\w匹配字母或数字或下划线或汉字等。
对中文/汉字的特殊处理是由.Net提供的正则表达式引擎支持的,其它环境下的具体情况请查看相关文档。
下面来看看更多的例子:
\ba\w*\b匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)。
好吧,现在我们说说正则表达式里的单词是什么意思吧:就是不少于一个的连续的\w。不错,这与学习英文时要背的成千上万个同名的东西的确关系不大 :)
\d+匹配1个或更多连续的数字。这里的+是和*类似的元字符,不同的是*匹配重复任意次(可能是0次),而+则匹配重复1次或更多次。
\b\w{6}\b 匹配刚好6个字符的单词。
表1.常用的元字符
匹配除换行符以外的任意字符
匹配字母或数字或下划线或汉字
匹配任意的空白符
匹配单词的开始或结束
匹配字符串的开始
匹配字符串的结束
正则表达式引擎通常会提供一个“测试指定的字符串是否匹配一个正则表达式”的方法,如JavaScript里的RegExp.test()方法或.NET里的Regex.IsMatch()方法。这里的匹配是指是字符串里有没有符合表达式规则的部分。如果不使用^和$的话,对于\d{5,12}而言,使用这样的方法就只能保证字符串里包含5到12连续位数字,而不是整个字符串就是5到12位数字。
元字符^(和数字6在同一个键位上的符号)和$都匹配一个位置,这和\b有点类似。^匹配你要用来查找的字符串的开头,$匹配结尾。这两个代码在验证输入的内容时非常有用,比如一个网站如果要求你填写的QQ号必须为5位到12位数字时,可以使用:^\d{5,12}$。
这里的{5,12}和前面介绍过的{2}是类似的,只不过{2}匹配只能不多不少重复2次,{5,12}则是重复的次数不能少于5次,不能多于12次,否则都不匹配。
因为使用了^和$,所以输入的整个字符串都要用来和\d{5,12}来匹配,也就是说整个输入必须是5到12个数字,因此如果输入的QQ号能匹配这个正则表达式的话,那就符合要求了。
和忽略大小写的选项类似,有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项,^和$的意义就变成了匹配行的开始处和结束处。
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.和\*。当然,要查找\本身,你也得用\\.
例如:unibetter\.com匹配unibetter.com,C:\\Windows匹配C:\Windows。
你已经看过了前面的*,+,{2},{5,12}这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码,例如*,{5,12}等):
表2.常用的限定符
重复零次或更多次
重复一次或更多次
重复零次或一次
重复n次或更多次
重复n到m次
下面是一些使用重复的例子:
Windows\d+匹配Windows后面跟1个或更多数字
^\w+匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)
要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办?
很简单,你只需要在方括号里列出它们就行了,像[aeiou]就匹配任何一个英文元音字母,[.?!]匹配标点符号(.或?或!)。
我们也可以轻松地指定一个字符范围,像[0-9]代表的含意与\d就是完全一致的:一位数字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考虑英文的话)。
下面是一个更复杂的表达式:\(?0\d{2}[) -]?\d{8}。
“(”和“)”也是元字符,后面的里会提到,所以在这里需要使用。
这个表达式可以匹配几种格式的电话号码,像(010),或022-,或等。我们对它进行一些分析吧:首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。
不幸的是,刚才那个表达式也能匹配010)或(022-这样的“不正确”的格式。要解决这个问题,我们需要用到分枝条件。正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。听不明白?没关系,看例子:
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-),一种是4位区号,7位本地号()。
\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。
\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(后面会有介绍)。
(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式,请按下列顺序分析它:\d{1,3}匹配1到3位的数字,(\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(\d{1,3})。
IP地址中每个数字都不能大于255,大家千万不要被《24》第三季的编剧给忽悠了……
不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。
理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?,这里我就不细说了,你自己应该能分析得出来它的意义。
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:
表3.常用的反义代码
匹配任意不是字母,数字,下划线,汉字的字符
匹配任意不是空白符的字符
匹配任意非数字的字符
匹配不是单词开头或结束的位置
匹配除了x以外的任意字符
匹配除了aeiou这几个字母以外的任意字符
例子:\S+匹配不包含空白符的字符串。
&a[^&]+&匹配用尖括号括起来的以a开头的字符串。
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
呃……其实,组号分配还不像我刚说得那么简单:
分组0对应整个正则表达式实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。难以理解?请看示例:
\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go
go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。
你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?&Word&\w+)(或者把尖括号换成'也行:(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k&Word&,所以上一个例子也可以写成这样:\b(?&Word&\w+)\b\s+\k&Word&\b。
使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:
表4.常用分组语法
匹配exp,并捕获文本到自动命名的组里
(?&name&exp)
匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
匹配exp,不捕获匹配的文本,也不给此分组分配组号
匹配exp前面的位置
匹配exp后面的位置
匹配后面跟的不是exp的位置
匹配前面不是exp的位置
(?#comment)
这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读
我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号。“我为什么会想要这样做?”——好问题,你觉得为什么呢?
地球人,是不是觉得这些术语名称太复杂,太难记了?我也有同感。知道有这么一种东西就行了,它叫什么,随它去吧!人若无名,便可专心练剑;物若无名,便可随意取舍……
接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。最好还是拿例子来说明吧:
断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm
singing while you're dancing.时,它会匹配sing和danc。
(?&=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?&=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading
a book时,它匹配ading。
假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?&=\d)\d{3})+\b,用它对进行查找时结果是。
下面这个例子同时使用了这两种断言:(?&=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)。
负向零宽断言
前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:
\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq
fighting。负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b。
零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
同理,我们可以用(?&!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?&![a-z])\d{7}匹配前面不是小写字母的七位数字。
请详细分析表达式(?&=&(\w+)&).*(?=&\/\1&),这个表达式最能表现零宽断言的真正用途。
一个更复杂的例子:(?&=&(\w+)&).*(?=&\/\1&)匹配不包含属性的简单HTML标签内里的内容。(?&=&(\w+)&)指定了这样的前缀:被尖括号括起来的单词(比如可能是&b&),然后是.*(任意的字符串),最后是一个后缀(?=&\/\1&)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是&b&的话,后缀就是&/b&了。整个表达式匹配的是&b&和&/b&之间的内容(再次提醒,不包括前缀和后缀本身)。
小括号的另一种用途是通过语法(?#comment)来包含注释。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。
要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以前面的一个表达式写成这样:
# 断言要匹配的文本的前缀
&(\w+)& # 查找尖括号括起来的字母或数字(即HTML/XML标签)
# 前缀结束
# 匹配任意文本
# 断言要匹配的文本的后缀
# 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
# 后缀结束
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:
a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The match that begins earliest wins。
表5.懒惰限定符
重复任意次,但尽可能少重复
重复1次或更多次,但尽可能少重复
重复0次或1次,但尽可能少重复
重复n到m次,但尽可能少重复
重复n次以上,但尽可能少重复
在C#中,你可以使用来设置正则表达式的处理选项。如:Regex regex = new Regex(@"\ba\w{6}\b", RegexOptions.IgnoreCase);
上面介绍了几个选项如忽略大小写,处理多行等,这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项:
表6.常用的处理选项
IgnoreCase(忽略大小写)
匹配时不区分大小写。
Multiline(多行模式)
更改^和$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)
Singleline(单行模式)
更改.的含义,使它与每一个字符匹配(包括换行符\n)。
IgnorePatternWhitespace(忽略空白)
忽略表达式中的非转义空白并启用由#标记的注释。
ExplicitCapture(显式捕获)
仅捕获已被显式命名的组。
一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。
平衡组/递归匹配
这里介绍的平衡组语法是由.Net Framework支持的;其它语言/库不一定支持这种功能,或者支持此功能但需要使用不同的语法。
有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如(
5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?
为了避免(和\(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把xx
&aa &bbb& &bbb& aa& yy这样的字符串里,最长的配对的尖括号内的内容捕获出来?
这里需要用到以下的语法构造:
(?'group') 把捕获的内容命名为group,并压入堆栈(Stack)(?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败(?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分(?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败
如果你不是一个程序员(或者你自称程序员但是不知道堆栈是什么东西),你就这样理解上面的三种语法吧:第一个就是在黑板上写一个"group",第二个就是从黑板上擦掉一个"group",第三个就是看黑板上写的还有没有"group",如果有就继续匹配yes部分,否则就匹配no部分。
我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空--如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。
#最外层的左括号
#最外层的左括号后面的不是括号的内容
(?'Open'&)
#碰到了左括号,在黑板上写一个"Open"
#匹配左括号后面的不是括号的内容
(?'-Open'&)
#碰到了右括号,擦掉一个"Open"
#匹配右括号后面不是括号的内容
(?(Open)(?!))
#在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败
#最外层的右括号
平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的&div&标签:&div[^&]*&[^&&]*(((?'Open'&div[^&]*&)[^&&]*)+((?'-Open'&/div&)[^&&]*)+)*(?(Open)(?!))&/div&.
还有些什么东西没提到
上边已经描述了构造正则表达式的大量元素,但是还有很多没有提到的东西。下面是一些未提到的元素的列表,包含语法和简单的说明。你可以在网上找到更详细的参考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到.net下正则表达式详细的文档。
这里的介绍很简略,如果你需要更详细的信息,而又没有在电脑上安装MSDN Library,可以查看。
表7.尚未详细讨论的语法
报警字符(打印它的效果是电脑嘀一声)
通常是单词分界位置,但如果在字符类里使用代表退格
制表符,Tab
竖向制表符
ASCII代码中八进制代码为nn的字符
ASCII代码中十六进制代码为nn的字符
Unicode代码中十六进制代码为nnnn的字符
ASCII控制字符。比如\cC代表Ctrl+C
字符串开头(类似^,但不受处理多行选项的影响)
字符串结尾或行尾(不受处理多行选项的影响)
字符串结尾(类似$,但不受处理多行选项的影响)
当前搜索的开头
Unicode中命名为name的字符类,例如\p{IsGreek}
贪婪子表达式
(?&x&-&y&exp)
(?im-nsx:exp)
在子表达式exp中改变处理选项
为表达式后面的部分改变处理选项
(?(exp)yes|no)
把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no
(?(exp)yes)
同上,只是使用空表达式作为no
(?(name)yes|no)
如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no
(?(name)yes)
同上,只是使用空表达式作为no
好吧,我承认,我骗了你,读到这里你肯定花了不止30分钟.相信我,这是我的错,而不是因为你太笨.我之所以说"30分钟",是为了让你有信心,有耐心继续下去.既然你看到了这里,那证明我的阴谋成功了.被忽悠的感觉很爽吧?
要投诉我,或者觉得我其实可以忽悠得更高明,欢迎来让我知道.
如果你有关于正则表达式的问题, 可以到
网站上提问, 记得要添加 regex 标签. 如果你更习惯于用中文交流,
可以到微博上用 #正则# 标签提出问题.
网上的资源及本文参考文献
第一版 第二版
修正了几个细节上的错误和不准确的地方增加了对处理中文时的一些说明更改了几个术语的翻译(采用了MSDN的翻译方式)增加了平衡组的介绍放弃了对The Regulator的介绍,改用Regex Tester V2.1
修正了几个小的错误增加了对处理选项(RegexOptions)的介绍 V2.2
重新组织了对零宽断言的介绍删除了几个不太合适的示例,添加了几个实用的示例其它一些微小的更改 V2.21
修改了几处文字错误修改/添加了对$,\b的精确说明承认了作者是个骗子给RegexTester添加了Singleline选项的相关功能 v2.3
调整了部分章节的次序修改了页面布局,删除了专门的参考节针对读者的反馈,调整了部分内容 v2.31
修改了几处文字错误添加了一些注释说明调整了一些措词 v2.32
更改了工具介绍,换用自行开发的正则表达式测试器
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/9701201
https://blog.csdn.net/zwj_506/article/details/9344673
https://blog.csdn.net/zwj_506/article/details/9344673
转载地址:http://www.cnblogs.com/iuices/archive//2247782.html & 写的很不错,对于正在求职的人很值得一看
& 基本上求职者进行笔试时没有不考字符串的。字符串也是一种相对简单的数据结构,容易引起面试官反复发问。事实上,字符串也是考验程序员编程规范和编程习惯的重要考点。不要忽视这些细节,因为这些细节会体现你在操作系统、软件工程、边界内存处理等方面的知识掌握能力,也会成为企业是否录用你的参考因素。
1、怎样将整数转换成字符串数,并且不用函数 itoa ?
&&& 答案:
&iostream&
using&namespace&
&&&&int&num
=12345,i=0,j=0;
&&&&char&temp[7],str[7];
&&&&while(num)
&&&&&&&&temp[i]=num%10+'0';
&&&&&&&&i++;
&&&&&&&&num=num/10;
&&&&temp[i]=0;
&&&&cout&&&temp:&&&temp&&
&&&&i=i-1;
&&&&while&(i&=0)
&&&&&&&&str[j++]=temp[i--];
&&&&str[j]=0;
&&&&cout&&&string:&&&str&&
&&&&return&0;
&&& 如果可以使用 itoa函数的话,则十分简单,如下:
&iostream&
&stdlib.h&
using&namespace&
&&&&int&num=12345;
&&&&char&str[7];
&&&&itoa(num,str,10);
&&&&cout&&&integer:&&&num&&endl&&&string:&&&str&&
&&&&return&0;
2、已知函数原型是 char *strcpy(char *strDest,const char *strSrc);,其中strDest是目的字符串,strSrc是源字符串。
&&& (1)不调用C++/C的字符串库函数,请编写strcpy函数。
&&& (2)strcpy函数把strSrc的内容复制到strDest,为什么还要char *类型返回值?
&&&&答案:
(1)代码如下:
char&*strcpy(char&*strDest,const&char&*strSrc)
&&&&assert((strDest!=NULL)&&(strSrc!=NULL));
&&&&char&*address=strD
&&&&while((*strDest++=*strSrc++)!='\0')
&&&&return&
(2)为了实现链式表达式,返回具体值。
int&length=strlen(strcpy(strDest,&hello
3、编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是& abcdefghi “,如果n=2,移位后应该是 “hiabcdefg ”。
&&&&答案:
(1)使用标准库函数方法:
void&LoopMove(char&*pStr,int&steps)
&&&&int&n=strlen(pStr)-
&&&&char&temp[MAX_LEN];
&&&&strcpy(temp,pStr+n);
&&&&strcpy(temp+steps,pStr);
&&&&*(temp+strlen(pStr))=‘\0’;
&&&&strcpy(pStr,temp);
(2)不使用标准库函数的方法:
(请看第五题和评论)
4、将一句话里的单词进行倒置,标点符号不倒置。比如一句话:i come from beijing.倒置后变成:beijing. from come i。
&&&&&&解析:解决该问题可以分为两步:第一步全盘置换该语句成:.gnijieb morf emoc i。第二步进行部分翻转,如果不是空格,则开始翻转单词。
&&&&&&答案:
具体代码如下:
&iostream&
using&namespace&
&&&&int&num=-12345,i=0,j=0,flag=0,begin,
&&&&char&str[]=&i
come from beijing.&;
&&&&j=strlen(str)-1;
&&&&while(j&i)
&&&&&&&&temp=str[i];
&&&&&&&&str[i++]=str[j];
&&&&&&&&str[j--]=
&&&&while(str[i])
&&&&&&&&if(str[i]!='
&&&&&&&&&&&&begin=i;
&&&&&&&&&&&&while(str[i]
&& str[i]!='
&&&&&&&&&&&&&&&&i++;&
&&&&&&&&&&&&i=i-1;&&&
&&&&&&&&&&&&end=i;
&&&&&&&&while(end&begin)
&&&&&&&&&&&&temp=str[begin];
&&&&&&&&&&&&str[begin++]=str[end];
&&&&&&&&&&&&str[end--]=
&&&&&&&&i++;
&&&&cout&&&string:&&&str&&
5、编程:输入一行字符串,找出其中出现的相同且长度最长的字符串,输出它及其首字符的位置。例如:“yyabcdabjcabceg”,输出结果应该为 abc和 3。
&&&&答案:
&iostream&
using&namespace&
&&&&string
&&&&cout&&&请输入字符串:&;
&&&&for(int&i=str.length()-1;i&1;i--)
&&&&&&&&for(int&j=0;j&str.length();j++)
&&&&&&&&&&&&if(j+i&=str.length())
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&size_t&t=0;
&&&&&&&&&&&&&&&&size_t&num=0;
&&&&&&&&&&&&&&&&tep=str.substr(j,i);
&&&&&&&&&&&&&&&&t=str.find(tep);&&&
&&&&&&&&&&&&&&&&num=str.rfind(tep);
&&&&&&&&&&&&&&&&if(t!=num)&&&&&&&&&
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&cout&&tep&&&
&&&t+1&&
&&&&&&&&&&&&&&&&&&&&return&0;
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&}
&&&&return&0;
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/9344673
https://blog.csdn.net/zwj_506/article/details/9343053
https://blog.csdn.net/zwj_506/article/details/9343053
说到面向对象,大家第一反应应该就是它的三大特性:封装性、继承性和多态性。那么我们先简单的了解一下这三大特性:
&&&& (1)封装性:封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
在C++中类中成员的属性有:public, protected, private,这三个属性的访问权限依次降低。
&&&& (2)继承性:继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
&&&& (3)多态性:多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有二种方式,覆盖,重载。
覆盖,是指子类重新定义父类的虚函数的做法。
重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
下面开始我们今天的学习。
1、C++中空类默认产生哪些类成员函数?
对于一个空类,编译器默认产生4个成员函数:
(1)默认构造函数
(2)析构函数
(3)拷贝构造函数
(4)赋值函数
2、结构是否可以有构造函数、析构函数及成员函数?如果可以,那么结构和类还有什么区别吗?
区别是class中变量默认是private,struct中的变量默认是public。class继承默认是private继承,而struct继承默认是public继承。struct可以有构造函数、析构函数,之间也可以继承甚至是多重继承,等等。C++中的struct其实和class意义一样,唯一不同就是struct里面默认的访问控制是public,class中默认访问控制是private。C++中存在struct关键字的唯一意义就是为了让C程序员有个归属感,是为了让C++编译器兼容以前用C开发的项目。
3、下面程序打印出的结果是什么?
#include&iostream&
using&namespace&
class&base
&&&&int&m_i;
&&&&int&m_j;
) : m_j(i),m_i(m_j) {}
&&&&base()
: m_j(0),m_i(m_j){}
&&&&int&get_i()
{return&m_i;}
&&&&int&get_j()
{return&m_j;}
&& obj.get_i() &&endl&& obj.get_j() &&
&&&&return&0;
解析:本题想得到的结果是“98,98”。但是成员变量的声明是先 m_i ,然后是 m_j;初始化列表的初始化变量顺序是根据成员变量的声明顺序来执行的,因此,先初始化 m_i,但此时 m_j 还未初始化,m_i 会被赋予一个随机值。改变一下成员变量的声明顺序可以得到预想的结果。
输出结果第一个为随机数,第二个是98。
4、下面这个类声明正确吗?为什么?
&&&&const&int&Size
解析:这道程序题存在着成员变量问题。常量必须在构造函数的初始化列表里初始化或者将其设置成static。
正确的程序如下:
&&&&&&&&const&int&Size
&&&&static&const&int&Size
5、析构函数可以为 virtual 型,构造函数则不能,为什么?
虚函数采用一种虚调用的办法。虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道接口而不知道其准确对象类型的函数。但是如果要创建一个对象,你势必要知道对象的准确类型,因此构造函数不能为 virtual。
6、如果虚函数是非常有效的,我们是否可以把每个函数都声明为虚函数?
不行,这是因为虚函数是有代价的:由于每个虚函数的对象都必须维护一个 v 表,因此在使用虚函数的时候会产生一个系统开销。如果仅是一个很小的类,且不行派生其他类,那么根本没必要使用虚函数。
7、请看下面一段程序:
#include&iostream&
using&namespace&
&&&&&&&&cout&&&defualt
constructor&&&
&&&&&&&&cout&&&destructed
&&&&&&&&cout&&&constructed
by parameter&&&data&&
Play( B b )
&&&&return&b;
temp = Play(5);
&&&&return&0;
&&&&&&&(1)该程序输出结果是什么?为什么会有这样的输出?
&&&&& (2)B( int i ) : data( i ),这种用法的专业术语叫什么?
&&&&& (3)Play( 5 ),形参类型是类,而5是个常量,这样写合法吗?为什么?
(1)输出结果如下:
constructed
by parameter
&&&&&&&destructed&&&&&&&&&
&&&&&&&destructed&&&&&&&&&&
(2)待参数的构造函数,冒号后面的是成员变量初始化列表(member initialization list)
(3)合法。单个参数的构造函数如果不添加explicit关键字,会定义一个隐含的类型转换;添加explicit关键字会消除这种隐含转换。
8、编写类 String 的构造函数、析构函数和赋值函数。
&&&&& 已知类 String 的原型为:
class&String
&&&&String(const&char&*str
= NULL);&&&&&&&&&&
&&&&String(const&String
&other);&&&&&&&&&&&&&
&&&&~String(void);&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&String
& operate =(const&String
&&&&char&*m_&&&&&&&&&&&&&&&&&&&&&&&&&&&&
1、 String 的析构函数:
String::~String(void)
&&&&delete&[]
2、String 的构造函数:
String::String(const&char&*str)
&&&&if(NULL==str)
&&&&&&&&m_data
= new&char[1];
&&&&&&&&*m_data
&&&&&&&&int&length
= strlen(str);
&&&&&&&&m_data
= new&char[length+1];
&&&&&&&&strcpy(m_data,str);
3、String的拷贝构造函数:
String::String(const&String
&&&&int&length
= strlen(other.m_data);
&&&&m_data
= new&char[length+1];
&&&&strcpy(m_data,other.m_data);
4、String的赋值函数:
& String::operate =(const&String
&&&&if(this==
&&&&&&&&return&*this;
&&&&delete&[]
&&&&int&length=strlen(other.m_data);
&&&&m_data
= new&char[length+1];
&&&&strcpy(m_data,other.m_data);
&&&&return&*this;&&&&
9、重载与覆盖有什么不同?
&&&& 虚函数总是在派生类中被改写,这种改写被称为“override”(覆盖)。
&&&& override 是指派生类重写基类的虚函数,重写的函数必须有一致的参数表和返回值。Override这个单词好像一直没什么合适的中文词汇来对应。有些人译为“覆盖”,还贴切一些。
&&&& overload约定成俗地被翻译为“重载”,是指编写一个与自己已有函数同名但是参数表不同的函数。例如一个函数既可以接受整型数作为参数,也可以接收浮点数作为参数。重载不是一种面向对象的编程,而是一种语法规则,重载与多态没什么直接关系。
作者:zwj_506 发表于
https://blog.csdn.net/zwj_506/article/details/9343053

我要回帖

更多关于 苹果手机流量消耗太快 的文章

 

随机推荐