因练习正则而感受到丰富的解题思路

不久前,在正则上终于可以登堂入室了,因担心久不练习而使其荒废,就在百度知道中不时的为他人用正则解决一些问题而练习.

 

偶而,在解决同一问题时,看到别人以不同方式和思路时,不由的心中窃喜,又学到了一招!

 

写代码程序员们都会,可是能想出独特解决思路的可不是人人都能具备的.能学到别人的思路可谓是提升自己思维的一大助力.


现摘几个小例子来看看.


用正则表达式查分下面字符串,拆分成字符串数组

  2011-11-10 10:28 提问者:j00710 | 悬赏分:20 | 浏览次数:85次

String s = "aa[兴奋]啊啊天天][...]b[?]bb[棒棒冰";

得到结果

String[] result = {"aa","[兴奋]","啊啊天天]","[...]","b","[?]","bb[棒棒冰"};


这是百度上的一个提问,我在看到题目后简单一分析,其实也很简单,就是以[...]这种格式来拆分字符串.先看看别人是怎么答的.嗯有一解法为

 

 

arr=s.split("[");
for(arr){
  arr[i].split("]");
}

 

 

这种写法不是JAVA的,而且方法也有问题,以[来分割,再以]来分割,那会多分的,如:[[[abc]a,应该分成[[,[abc],a结果呢?,唉,惨不忍睹.

没有好的解法,那我就来写个.

我的第一种解决思路是,以全局的正则来匹配,匹配时分两种情况,如果有[...]格式,则以取前缀和匹配格式,如果没有,则取所有字符.这种JAVA的写法代码较长,但很实用.写出正则 (?:(.*?)(\\[[^]]*\\]))|(.+$) 这里有三个捕获型括号,可以取到各部分的值,再写出代码

 

String eg="(?:(.*?)(\\[[^]]*\\]))|(.+$)";
 Matcher m = Pattern.compile(eg, Pattern.CASE_INSENSITIVE).matcher(str);
ArrayList list = new ArrayList();
while (m.find()) {
            if(m.group(1)!=null)list.add(m.group(1));
            if(m.group(2)!=null)list.add(m.group(2));
            if(m.group(3)!=null)list.add(m.group(3));
}
System.out.println(list); 
 

 

测试,有乱码.晕,是带有双字节字符的,那就再加上个unicode支持吧,把Pattern.CASE_INSENSITIVE改成Pattern.CASE_INSENSITIVE|Pattern.UNICODE_CASE.

再测试,成功.


可这代码,感觉太多了.就又想了一个解决思路.在[...]格式的前后插入特殊字符,再以特殊字符分割,只是这个字符串里不能含有特殊字符了,这里我选用了[]

String[] result = str.replaceAll("(\\[[^]]*\\])", "[]$1[]").split("\\[\\]")
 

 

本来我想这已经是最简单的了,但后来一位回答者又给出了一种思路.

Pattern p = Pattern.compile("(?=\\[.*?\\])|(?<=\\])");
String[] items = p.split(s); 
 

 

(其实这个可以写成String[] ss = str.replaseAll((?=\\[.*?\\])|(?<=\\]));)


这种思路是以位置来分割,我的是以特殊字符来分割.虽然这个解法也有限制,对于右位置判断正确,但左位置限制了]

这三种方法各有优劣,第一种是代码量太多,但最准.第二种代码较少,但限制了字符串中不能有[]这种字符.第三种最简单,但限制也最大,只有在无]]时才会准确.

不管怎么样,又学了一招,可用位置来分割.


还有一个问题.


一道java编程题

检举 | 2011-11-12 14:19 提问者:低调de狂 | 悬赏分:30 | 浏览次数:52次

随便输入一段字符串,把出现次数最多的打印出来,如:aabbbbbbbbbcccdffff,就把b打印出来,用java代码实现


这个问题如果是以前我是会想到把字符串中的每个字符进行记数,但现在我会是想到用正则来解决,先看看别人的解法,其中一位的思路给了我新的启发.

第一种解法.

 // 转成字符数组处理
		char[] cArray = str.toCharArray();
		Map<Character, Integer> map = new HashMap<Character, Integer>();
		// 统计各字符出现次数
		for (char c : cArray) {
			Integer count = map.get(c);
			if (null == count) {//第一次在map中是不可能找到该字符串的,我们直接给Integer加1
				map.put(c, 1);
			} else {
				map.put(c, count + 1);//之后的都先取出出现的次数,在他的Integer基础上加1
			}
		}
		int maxCount = 0;
		char mostChar = '0';
		// 比较获得出现次数最多的字符
		for (Map.Entry<Character, Integer> entry : map.entrySet()) {//map类型的迭代
			if (entry.getValue() > maxCount) {
				maxCount = entry.getValue();
				mostChar = entry.getKey();
			}
		}
		// 打印出结果
		System.out.println(mostChar);
 

 

 

这位的思路是遍历字符数组,把每个不同的字符都放到map中,如果有重复的就对计数加1,最后再遍历记数算,找到出现最多次数的字符.


第二种的解法,这种解法对我触动很大.

char[] help = new char[26];
	   for(int i=0;i<src.length();i++)
		   help[src.charAt(i)-'a']++;
	   int maxtimes=0;
	   char res = 0;
	   for(int i=0;i<26;i++)
		   if(help[i]>maxtimes) {
			   maxtimes=help[i];
			   res=(char)('a'+i);
		   }
	   return res;
   

 

这位的思路是预先放好26个字节长的字符数组,第一次遍历字符串,将每个字符去减a字符,这样得到的数值就是字符数组的相对下标,再向数组中记数加1,最后遍历字符数组,找出最大数值的下标,加上a就是最长的字符.


我的解决思路是利用正则.

String s = "aabbbbbbbbbcccdffff";
		Matcher m = Pattern.compile("((.)\\2*)").matcher(s);
		String l = "";
		while (m.find()) {
			l = l.length() < m.group(1).length() ? m.group(1) : l;
		}
		System.out.println(l.charAt(0)); 
 

 

 


这里三种解法,第一种是最正统的,用的最多的.第二种是有限制的,只能是小写字母的字符串,但最有启发性,第三种是对于正则有熟练的掌握性


这里暂时先讲这两个问题,希望能引出更多解题思路的朋友.

 

你可能感兴趣的:(编程,正则表达式)