A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 zeus00456 于 2014-7-20 15:00 编辑

下面直接进入正题吧

首先给出测试用的代码,为了节省版面,在格式上我就不讲究了哈
---------------------------------public class RegexDemo2 {
        public static void main(String[] args) {
                functionDemo_1();
                functionDemo_2();
        }
        public static void functionDemo_2(){//切割
                String str = "dzzzzhangsanaaaaad"
                String regex = "切割正则式";
               
                String[] names = str.split(regex);
                System.out.println(str+"    "+regex);
                for(String name : names){
                        System.out.println(name);
                }
        }
        public static void functionDemo_1(){//匹配
                String tel = "ab";               
                String regex = "匹配正则式";   
               
                boolean b = tel.matches(regex);
                System.out.println(tel+"    "+regex+"    "+b);
        }
}
---------------------------------
疑问来源,请参见 functionDemo_2()
对于字符串"dzzzzhangsanaaaaad",可以使用正则表达式"(.)\\1+"识别重复字符,并以之为界切割拆分原字符串
疑问是:+代表一次或多次,每个字符会匹配到正则中的(.)因为这个字符已经出现了一次,按理说,拆分的结果应该是将整个字符串的每一个字符打散,但是运行时为什么没有这样执行?这说明单个字符没有匹配到(.)+,因为\\1是个组的标号而已嘛,程序没有用到被标号的租的引用($1),所以我就忽略不计了
(先请看完整个帖子,帖子后我会将问题归纳一下)
---------------------------------
测试 1
这个问题出现后我查询了API,发现了这样一段话

组和捕获
如果由于量化的缘故再次计算了组,则在第二次计算失败时将保留其以前捕获的值(如果有的话)例如,将字符串 "aba" 与表达式 (a(b)?)+ 相匹配,会将第二组设置为 "b"。

然后我就试验了上面提到的 "aba" 和 (a(b)?)+的匹配,因为只看懂了这两个式子
结果返回了 true,然后我参悟了很久


正则式(a(b)?)+会判断字符串"aba"中是否包含一个或多个(a(b)?)———仅一个a后面仅有一个或没有b。
第一次,正则匹配到了"ab",一个a一个b,通过
第二次,正则匹配到了"a",一个a没有b,通过
字符串结束每次匹配都通过,返回true
---------------------------------
测试 2
然后,我测试了"aba" 和 (ab?)+,与前一个的不同是少了一个组
结果毫无疑问的返回了true


突然我开始疑惑用来划分组的()有什么用了
于是用切割功能进行了下面两个测试
结果很明显,


字符串会严格的匹配整个组的内容,也就是说,组可以划分出一个大规则中的小规则并且将这个小规则作为匹配的单位
就好像if()某语句  和  if(){语句段}    中{}的作用
我发现有些2了,但是各位发现没,"aba" 和 (ab?)+与问题来源挺像的,是判断一个符合某种规则的表达是出现一次或多次,但是这两个匹配成功了(原问题中没有!)
---------------------------------
测试 3
我回过头思考最一开始的问题(被我带的思路跑偏的童鞋不妨回头看一眼),然后开始怀疑是不是正则组是专门用来匹配重复的?
因为最早的问题中,正则组没有对单个不重复的字符进行匹配,而测试二中则匹配上了重复的字段,这个解释至少从现象上是行得通的
于是测试了"ab" 和 (ab?)+ 但是结果
很明显,猜测不正确,()+的组和是可以匹配单次的!
也就是说,造成正则表达式没有匹配到单个字符,不是()+造成的
---------------------------------
测试 4
既然如此,我想可能是两个原因造成的
split方法有独特的匹配方式和"."(因为刚刚的测试使用的是matches方法和给定的字母
对于前者连我自己都感觉很扯,找遍了API也没有发现关于“独特的匹配方式”的哪怕半句描述
那只能是 "."了吧,我如是想。
于是我测试了"dzzzzhangsanaaaaad"和(.)+,结果如下

???!!!
我觉得我找到病根了,没拆出来!
但是我很快发现我错了,没拆出来应该直接输出原字符串的
这是匹配出来的结果,可是怎么什么都没有呢,然后我发现了这一句
这是因为字符串的每一个字符都匹配正则,每个字符都被切了一刀,切后的字符串数组是{"","","",……}于是都被当做结尾空串舍弃了,于是控制台上什么都没有,被我饶晕的童鞋可以看这个图


---------------------------------
测试 5
直到现在,结果已经很明显了,真相永远只有一个,凶手是被我一直忽略的"\\1"
验证一下,果然!刚刚明明是true的啊




---------------------------------
现在,出现了两个问题
1.没有标号,仅仅是一个(),这种写法是圈定了一个正则组吗?
2."\\1"这货,到底在正则中起了什么作?


这两个问题到现在我都没弄懂
---------------------------------
推测
API中与"\\1"相关的描述似乎都集中在了下面的描述中:
之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器获取。
与组关联的捕获输入始终是与组最近匹配的子序列。如果由于量化的缘故再次计算了组,则在第二次计算失败时将保留其以前捕获的值(如果有的话)例如,将字符串 "aba" 与表达式 (a(b)?)+ 相匹配,会将第二组设置为 "b"。在每个匹配的开头,所有捕获的输入都会被丢弃。




2014-07-20_144643.jpg (4.27 KB, 下载次数: 2)

2014-07-20_144643.jpg

2 个回复

倒序浏览
本帖最后由 zeus00456 于 2014-7-20 15:03 编辑

帖子居然还能超出长度?= =||

呈上文
--------以下内容都为推测------------
看上面的意思
back是一个匹配正则式结果的地方,它可能是一个字符串数组,其0索引处始终存着整个正则表达式,当遇到一个组时,会将匹配到的结果保存到back中,保存的位置有\\n指定,未指定时使用\\0,并将结果用于下一次匹配。

以"dzzzh"和"(.)\\1+"为例
正则开始匹配,back ={ "(.)\\1+"}
(.)捕获d,\\1将这个捕获结果输入到back的1索引处,此时 back ={ "(.)\\1+","d"}
(.)捕获z,用back中1索引处的d进行匹配,失败,并将z输入到back的1索引处,此时 back ={ "(.)\\1+","z"}
(.)捕获z,用back中1索引处的z进行匹配,成功, ,此时 back ={ "(.)\\1+","z"}
(.)捕获z,用back中1索引处的z进行匹配,成功,  ,此时 back ={ "(.)\\1+","z"}
(.)捕获h,用back中1索引处的z进行匹配,失败,此时判定前面的"(.)\\1+"匹配成功,切割字符串,
并将h输入到back的1索引处,此时 back ={ "(.)\\1+","h"}
字符串匹配至末尾,匹配成功一次,切了一刀


用这样的理解方法,可以粗浅的解释\\n的作用,但是各位也见到了,很粗浅
而且不能解释 的正则判断流程
其实,写的这一部分我的思路已经乱了,相比各位也看出来了
归纳一下疑问吧
1.没有标号,仅仅是一个(),这种写法是圈定了一个正则组吗?
2."\\1"这货,到底在正则中起了什么作?
3.Back是什么与我想的是一样/类似的吗?
诚挚的欢迎楼下的童鞋们指教/交流




回复 使用道具 举报
求回复呀谢谢
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马