`
RednaxelaFX
  • 浏览: 3019119 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

见《java字符串解析》,联想

阅读更多
JavaEye问答:java字符串解析

本来想回那帖的,但从学校坐了趟公交回到住处那问题就已经关闭了 T T
其实我是想说,这问题用正则表达式解决是如此的简单……因为那帖给的字符串是有规律的:带有相同数字的项是相邻的

例如说用Ruby的话,在irb里测试一下:
irb(main):001:0> src = '22:w,22:c,21:r,7:r,7:w,7:c,8:w,8:c,8:d,9:r,9:w,9:c,9:d,10:r'
=> "22:w,22:c,21:r,7:r,7:w,7:c,8:w,8:c,8:d,9:r,9:w,9:c,9:d,10:r"
irb(main):002:0> re = /((\d+):\w(,\2:\w)*),/
=> /((\d+):\w(,\2:\w)*),/
irb(main):003:0> expected_result = '22:w,22:c;21:r;7:r,7:w,7:c;8:w,8:c,8:d;9:r,9:w,9:c,9:d;10:r'
irb(main):004:0> result = src.gsub re, '\1;'
=> "22:w,22:c;21:r;7:r,7:w,7:c;8:w,8:c,8:d;9:r,9:w,9:c,9:d;10:r"
irb(main):005:0> result == expected_result
=> true


也就是说那个问题用一行代码的函数就能解决:
def reformat(src)
  src.gsub /((\d+):\w(,\2:\w)*),/, '\1;'
end


即便用Java也仍然是同样的简单:
public class TestRegex {
    public static String reformat(String src) {
        return src.replaceAll("((\\d+):\\w(,\\2:\\w)*),", "$1;");
    }
    
    public static void main(String[] args) {
        String src = "22:w,22:c,21:r,7:r,7:w,7:c,8:w,8:c,8:d,9:r,9:w,9:c,9:d,10:r";
        String expected = "22:w,22:c;21:r;7:r,7:w,7:c;8:w,8:c,8:d;9:r,9:w,9:c,9:d;10:r";
        String result = reformat(src);
        System.out.println(result.equals(expected));
    }
}


当然如果输入的字符串没有上述的特殊属性就无法保证这个方法的正确性了。只不过我猜那个问题原本作为源的字符串就是从什么别的程序输出得到的,或许本来就有这样的规律,值得利用。
分享到:
评论
2 楼 RednaxelaFX 2008-12-11  
呵呵,印象中在CSDN没注册,那边貌似不注册回不了,就算了。
不介意的话,这里稍微解释一下上面的正则表达式:
Ruby写法:
/((\d+):\w(,\2:\w)*),/

这代表一个正则表达式常量。两个斜杠('/')之间的是正则表达式的内容。
Java的写法与其十分相似:
new Pattern("((\\d+):\\w(,\\2:\\w)*),")

Java里正则表达式是用java.util.regex.Pattern对象来表示的,用一个String来表示正则表达式的内容。注意到由于字符串里反斜杠('\')是转义字符,需要写成两个反斜杠("\\")才可以表示正则表达式里的一个反斜杠。就内容来看,这里Ruby跟Java的正则表达式都是一样的。它们使用的都是大致上与Perl的正则表达式兼容的记法。

在这种记法里,\d能匹配一个数字(也就是[0-9]),\w能匹配一个单词字符(也就是[_0-9a-zA-Z]);+代表匹配次数为一次或更多次,*代表匹配次数为零次或更多次;圆括号(())代表一个捕获分组,捕获分组根据其左括号出现的顺序而编号。这个例子里出现的其它字符都是普通字符,直接用于匹配。

也就是说,\d能够匹配0到9的任意一个字符。但事先无法确定这个问题中作为编号的数字有多长,所以用\d+来匹配任意长度大于或等于1的数字;把这个\d+用圆括号括起来是为了后面能够使用捕获到的值。
接下来是冒号(':'),就是用来匹配冒号。\w用来匹配一个单词字符(这个限制可能松了点,或许应该用[a-z]的,但我不清楚那个字符串里可能会出现什么,干脆就松一点了)。
然后又是一个分组。里面先是一个逗号,用于匹配逗号;\2表示这里要匹配之前(\d+)这个分组所捕获到的内容,然后冒号匹配冒号,\w匹配一个单词字符。这个分组后面的星号('*')表示这个分组可以匹配任意多次。
前面的整个表达式外面被一组圆括号包围起来,作为第一个分组。这个分组后面是一个逗号,用于匹配一个逗号。

那么在匹配22:w,22:c,21:r的时候,
首先\d+匹配到了22,捕获为第二个分组;然后:和w依次被匹配。接下来进到可以出现任意多次的分组,先匹配一个逗号,然后是22,然后:和c。再接下来试图匹配逗号之后,21与22不匹配,于是这个分组的匹配就结束了。整个22:w,22:c就被捕获为第一个分组(也就是\1)。最后再把21之前的逗号匹配掉,这个正则表达式的匹配就结束了。
替换的时候,由于先前匹配的捕获分组的信息还保留着,可以用于替换操作。此时被替换的内容是"22:w,22:c,",注意那个逗号也被匹配进去了;替换它的内容是第一个分组的内容外加一个分号:Ruby中的"\1;"或者Java中的"$1;"。没有被替换的内容是21:r。于是替换完成后就变成了"22:w,22:c;21:r"。

这样,应用replaceAll()之类的方法就能把所有连续出现的"数字:字符"序列用分号分开了。

要更详细的了解正则表达式的话,恐怕还是得多读资料多实验一下。我喜欢用Ruby来试正则表达式,主要是因为那个交互式解释器方便。
1 楼 flyong 2008-12-10  
学习了,
上面的正则表达式看不懂,楼主很强,要学习正则了,
http://topic.csdn.net/u/20081209/13/93C87E59-BF06-4FCA-BDC8-D70D2924404D.html

是我在其他地方发的帖子,楼主可以回复一下,就关闭了

相关推荐

Global site tag (gtag.js) - Google Analytics