不久前,在正则上终于可以登堂入室了,因担心久不练习而使其荒废,就在百度知道中不时的为他人用正则解决一些问题而练习.
偶而,在解决同一问题时,看到别人以不同方式和思路时,不由的心中窃喜,又学到了一招!
写代码程序员们都会,可是能想出独特解决思路的可不是人人都能具备的.能学到别人的思路可谓是提升自己思维的一大助力.
现摘几个小例子来看看.
用正则表达式查分下面字符串,拆分成字符串数组
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));
这里三种解法,第一种是最正统的,用的最多的.第二种是有限制的,只能是小写字母的字符串,但最有启发性,第三种是对于正则有熟练的掌握性
这里暂时先讲这两个问题,希望能引出更多解题思路的朋友.