正则表达式日常

    在工作中由于自己的任务分配经常处理正则表达式的问题,不过如果要我正经写一个文章可能比较困难,这篇博文就当作日常积累吧。
   
    (2010.03.26)占有优先量词的使用:
    想要取出文档中所有以#开头,ascii字符为内容,空格或者{为结束的字符串,比如对"#loading {"就是取出loading,方法当然很容易,用java写的匹配Pattern就是
    Pattern p = Pattern.compile("#(\\w+)[\\s{]?");

    因为考虑不周,发现这个会把"#health:focus"中的health也取出,但我不想让这种类型匹配成功,所以决定对所有后面有":"的不予匹配,先试着用了否定正向环视
    Pattern p = Pattern.compile("#(\\w+)(?!:)[\\s{]?");

     但由于即使+是贪婪的,可还是以整个正则的的匹配成功为前提,所以导致会取出"headth:"的"healt"部分,仍然匹配成功。我想了一下,如果不怕麻烦,可以把(\\w+)后的字符取出来判断是否为":",然则这就需要两步了,用perl的话语法很方便倒还可以,但java的Pattern方法不太合适。
    翻了翻精通正则表达式,正好找到我这里需要的即Possessive quantifiers,一旦占有就不会交出已匹配字符,即使这样会导致整个正则的匹配失败,那么就很简单了
    Pattern p = Pattern.compile("#(\\w++)(?!:)[\\s{]?");


    (2010.04.02)高级查找替换对比原地查找替换
    在正则的日常运用中,不接触替换几乎是不可能的,一般来说,仅使用String方法的replaceAll就可以满足大部分需求,但如果想要对替换的部分进行处理(可能只是简单的大小写替换)就非常困难,必须要使用Matcher的一些方法,对比一下:
    1) 对字符串的数字(仅整形)前后加上括号,这个只要replaceAll就可以
String s= "this is a number 123 and 456";
s = s.replaceAll("\\d+", "\"$0\"");

    2) 将字符串内的大写转为小写,由于无法对$n进行操作,所以必须借助Matcher
StringBuffer sb = new StringBuffer("there are DAXIE letters XIXI");
Pattern p = Pattern.compile("[A-Z]");
Matcher m = p.matcher(sb);
while(m.find())
{
    sb.replace(m.start(), m.end(), m.group().toLowerCase());
}

    3) 对字符串里的浮点数字进行四舍五入,只考虑小数点两遍都有数字的标准形式,因为存在变长,所以用replace的时候就必须重设Matcher的偏移,这里不仅有去掉分数部分的差异还有可能进位的差异
StringBuffer sb = new StringBuffer("this is a number 123.456 and 456.789 or 999.999");
Pattern p = Pattern.compile("(\\d+)\\.(\\d+)");
Matcher m = p.matcher(sb);
int index = 0;
while(m.find(index))
{
    String integer = m.group(1);
    String fraction = m.group(2);
    int i1 = Integer.parseInt(integer);
    int i2 = Integer.parseInt(fraction.substring(0, 1));
    if (i2 >= 5)
    {
        i1++;
    }
    String replace = String.valueOf(i1);
    index = m.end() - (m.group().length() - replace.length());
    sb.replace(m.start(), m.end(), replace);
}

请注意最后index的赋值以及次序,有些微妙的错误可能会发生
    4) 需求同上,不过使用了Matcher的高级替换方法,相应就明了了很多,最重要的是不用在意那该死的偏移了
StringBuffer sb = new StringBuffer();
Pattern p = Pattern.compile("(\\d+)\\.(\\d+)");
String s = "this is a number 123.456 and 456.789 or 999.999";
Matcher m = p.matcher(s);
while(m.find())
{
    String integer = m.group(1);
    String fraction = m.group(2);
    int i1 = Integer.parseInt(integer);
    int i2 = Integer.parseInt(fraction.substring(0, 1));
    if (i2 >= 5)
    {
        i1++;
    }
    m.appendReplacement(sb, String.valueOf(i1));
}
m.appendTail(sb);

   
    (2010.4.30)Java正则的逆向环视之殇:
    需求仍然是相当明确,为了要取出html内嵌js代码段内容,我们使用了类似<scirpt [^>]*>(.*?)</script)的正则,当然这里是极度简化了的,如果是按照html规范来的话,只要用户写的格式正确,那么是可以取出内容的,可用户会写不合规范的自闭合script标签,比如这种情况
<script type="text/javascript" src="script/CodeAssist.js" />
<script type="text/javascript">
var i = 100;
</script> 

那么取出来的就成了
<script type="text/javascript">
var i = 100;

    处理方法也不复杂,只要script开始标签的那个闭合>左边不是/就可以了,但实际上/到>间是可以随意写空格的,而java的逆向环视不能是不定数目的元素,一般来说折中处理方法是用比如{0, 100}来模拟不定数目,谁也不会吃饱了撑的写一百个以上的空格吧,但这毕竟在理论上就不对了。

    (2010.6.21)Xcode项目中使用正泽表达式
    首先下载正则包 RegexKitLite,解压后只需要将其中的RegexKitLite的m和h文件放入项目,再在项目的链接选项Other Linker Flags里添加-licucore即可。用起来方法也差不多,比如验证一个字符串是否为仅有空字符组成:
+ (BOOL)isBlankString:(NSString*)string
{
	return [string isMatchedByRegex:@"^\\s*$"];
}

    当然也有微妙的地方啦,比如这里的Match方法就必须要加上头和尾的标记,否则只相当于Java正则里面的find方法,其他就自己揣摩吧。

你可能感兴趣的:(java,.net,正则表达式,xcode,perl)