-、分组提取
以apache log为例,如下:
192.168.1.138 - - [03/Feb/2006:01:40:20 +0800] "GET /phpinfo.php HTTP/1.1" 404 295
//分别为 客户端IP、访问日期、请求路径、服务端响应Code、请求文件大小
其正则表达式为:
String pattern=
"^([\\d.]+)(\\S+)(\\S+)\\[([\\w:/]+\\s[+|-]\\d{4})\\]\\s\"(.+)\"\\s(\\d{3})\\s(\\d+)";
想到上面正则中括号()的作用了么?可以通过group(i)快速的将每组()中内容提取出来。
第一组([\d.]+):将IP地址匹配出来
第四组([\w:/]+\s[+|-]\d{4}):将时间匹配出来
第五组(.+):将客户端请求内容匹配出来
第六组(\d{3}):将服务端响应Code匹配出来
第七组(\d+):将文件大小匹配出来
</td> </tr> </table>
测试程序: import java.util.regex.*; public class Test { public static void main(String[] args) { String pattern="^([\\d.]+)(\\S+)(\\S+)\\[([\\w:/]+\\s[+|-]\\d{4})\\]\\s\"(.+)\"\\s(\\d{3})\\s(\\d+)"; String log="192.168.1.138--[03/Feb/2006:01:40:20 +0800] \"Get /phpinfo.php HTTP/1.1\" 404 295"; System.out.println("pattern: " + pattern); System.out.println("log: " + log); Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(log); if (m.find()) { System.out.println("IP Address: " + m.group(1)); System.out.println("Date&Time: " + m.group(4)); System.out.println("Request: " + m.group(5)); System.out.println("Response: " + m.group(6)); System.out.println("Size: " + m.group(7)); } else { System.out.println("error!"); } } } 程序输出: C:\java>java Test pattern: ^([\d.]+)(\S+)(\S+)\[([\w:/]+\s[+|-]\d{4})\]\s"(.+)"\s(\d{3})\s(\d+) log: 192.168.1.138--[03/Feb/2006:01:40:20 +0800] "Get /phpinfo.php HTTP/1.1" 404 295 IP Address: 192.168.1.138 Date&Time: 03/Feb/2006:01:40:20 +0800 Request: Get /phpinfo.php HTTP/1.1 Response: 404 Size: 295 二、替换匹配的字符串 假如需要替换掉匹配正则表达式的字符串,我们可以自已使用String类的subString()方法, 但jdk1.4的正则表达式API中提供了实现此功能的相关方法,如下: * replaceAll(newString); 替换全部符合正则表达式的子串为newString. * appendReplacement(StringBuffer, newString); 将字符串中匹配正则的 子串之前的字符串先传入到StringBuffer中,然后再加上newString。 * appendTail(StringBuffer); 将字符串中匹配最后一个正则表达式后面的 字符串传入到StringBuffer(通常和appendReplacement一起使用). 看下面的例子: import java.util.regex.*; public class Test{ public static void main(String[] args) { // 匹配d开头,接着是a或e最少一次,最多2次,再接着是mon // 感觉自已跟唐僧一样,N啰嗦 -__-!! String pattern ="d[ae]{1,2}mon"; String input ="Unix hath demons and deamons in it!"; System.out.println("Input:" + input); Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(input); // 两个子串符合: demons, deamons. System.out.println("ReplaceAll:A=" + m.replaceAll("A")); m.reset(); StringBuffer sb = new StringBuffer(); System.out.println("Append methods:"); while (m.find()) { m.appendReplacement(sb,"B"); System.out.println(sb); } m.appendTail(sb); System.out.println(sb.toString()); } } 运行结果: C:\java>java Test Input:Unix hath demons and deamons in it! ReplaceAll:A=Unix hath As and As in it! Append methods: Unix hath B Unix hath Bs and B Unix hath Bs and Bs in it! 三、查找 有时候你需要把字符串中匹配正则表达式的那一段找出来,接着前一个例子, 你可以调用“查找”方法成功后,调用下面的方法将匹配的字符串找出来。 start(), end() 返回字符串中匹配正则表达式的子串的开始位置和结束位置 groupCount() 返回()号匹配的数目,如果有的话。返回0表示没有使用()组,下面将会有介绍 group(int i) 返回正则表达式()匹配的第i组,如果i小于或等于groupCount()则返回相应的()匹配值, 如果调用group(0)或group()则返回整个匹配正则表达式的部分 下面这个例子使用group()直接将整个匹配正则表达式的子字符串取出来: import java.util.regex.*; public class Test2{ public static void main(String[] args) { // 匹配Q开头,第二个字符不为u,后面接数字1次或多次,后面再.号 String pattern ="Q[^u]\\d+\\."; Pattern p = Pattern.compile(pattern); String line ="Order QT300. Now !"; Matcher m = p.matcher(line); if (m.find()) { // m.group()须调用相关查找方法成功后才能调用 System.out.println(pattern + " matches \"" + m.group() +"\" in \"" + line +"\""); } else { System.out.println("NO MATCH"); } } } // 输出:Q[^u]\d+\. matches "QT300." in "Order QT300. Now !" 上面这个例子也可以使用start(), end()方法来完成: import java.util.regex.*; public class Test3{ public static void main(String[] args) { String pattern = "Q[^u]\\d+\\."; Pattern p = Pattern.compile(pattern); String line = "Order QT300. Now!"; Matcher m = p.matcher(line); if (m.find()) { System.out.println(pattern + " matches \"" + line.substring(m.start(), m.end()) + "\" in \"" + line + "\""); } else { System.out.println("NO MATCH!"); } } } // 输出:Q[^u]\d+\. matches "QT300." in "Order QT300. Now !" 四、转换 假设你想将字符串: Smith, John 通过正则转换为: John Smith 可以这样做: import java.util.regex.*; public class Test4{ public static void main(String[] args) { String line = "Smith, John"; // 这就是上面所说的()号,如果调用groupCount()的话,将输出2 // 匹配任何字符0次或多次,然后是","号和空格,再匹配任何字符0次和多次 // 上面的任何字符不包括换行符 Pattern p = Pattern.compile("(.*), (.*)"); Matcher m = p.matcher(line); if (m.find()) { // 先取上面正则()中匹配的group 2,也就是John // 然后再取()中匹配的group 1,也就是Smith System.out.println(m.group(2) + " " + m.group(1)); } else { System.out.println("NO MATCH!"); } } } // 输出: John Smith 再看一个例子:交换两个参数的位置 import java.util.regex.Pattern; import java.util.regex.Matcher; public class RearrangeText { public static void main(String args[]) { String regEx = "(Math.pow)"+ // Math.pow "\\s*\\(" + // Opening parenthesis "\\s*([+|-]?(\\d+\\.?\\d*|\\.\\d+)|([a-zA-Z]\\w*))" + // First argument "\\s*,\\s*" + // Comma "([+|-]?(\\d+\\.?\\d*|\\.\\d+)|([a-zA-Z]\\w*))" + // Second argument "\\s*\\)"; // Closing parenthesis String oldCode = "double result = Math.pow( 3.0, 16.0); " + "\ndouble resultSquared = Math.pow(2 ,result );"+ "\ndouble hypotenuse = Math.sqrt(Math.pow(2.0, 30.0)+Math.pow(2 , 40.0));"; Pattern pattern = Pattern.compile(regEx); Matcher m = pattern.matcher(oldCode); StringBuffer newCode = new StringBuffer(); while(m.find()) { m.appendReplacement(newCode, "$1\\($5,$2\\)");//$1表示第一组,$i表示第i组 //System.out.println("OK="+newCode); } m.appendTail(newCode); System.out.println("Original Code:\n"+oldCode.toString()); System.out.println("\nNew Code:\n"+newCode.toString()); } } 运行结果: C:\java>java RearrangeText Original Code: double result = Math.pow( 3.0, 16.0); double resultSquared = Math.pow(2 ,result ); double hypotenuse = Math.sqrt(Math.pow(2.0, 30.0)+Math.pow(2 , 40.0)); New Code: double result = Math.pow(16.0,3.0); double resultSquared = Math.pow(result,2); double hypotenuse = Math.sqrt(Math.pow(30.0,2.0)+Math.pow(40.0,2)); 五、匹配 在java中我们可以简单的使用String类的matches()方法来判断当前字符串是否符合 你所给定的正则表达式模式。matches()方法接受正则表达式做为参数,返回boolean类型。 if (inputString.matches(regexPattern)) { // 字符串inputString匹配regexPattern这个模式 } 代码很简单,但是效率不高,如果在程序中使用不止一次,我们可以使用Pattern和Matcher,例子见下: import java.util.regex.*; public class Test5{ public static void main(String[] args) throws PatternSyntaxException { String pattern = "^Q[^u]\\d+\\."; String input = "Qa777. is the next flight. It is on time."; Pattern p = Pattern.compile(pattern); boolean found = p.matcher(input).lookingAt(); System.out.println("'" + pattern + "'" + (found ? " matches '" : " doesn't match '") + input + "'"); } } 运行结果 C:\java>java Test5 '^Q[^u]\d+\.' matches 'Qa777. is the next flight. It is on time.' 六、小结: 在程序中使用正则表达式的步骤一般如下: 1. 建立Pattern对象,通过静态方法Pattern.compile(); 2. 取得Matcher对象,通过pattern.matcher(CharSequence charSequence); 3. 调用Matcher对象的相关查找方法。 java.lang.CharSequence接口是在JDK1.4版本中被添加进来的,它为不同种类的char序列 提供了统一的只读访问。实现的类有String, StringBuffer, java.nio.CharBuffer Matcher提供几个不同的查找方法,比String类的matches()方法更灵活,如下: match() 使用整个字符串与相关模式相比较,和String的matches()差不多 lookingAt() 从字符串开头的地方与相关模式比较 find() 匹配字符串,没有必要从字符串的第一个字符开始,如果前一个操作匹配, 而且匹配器没有重置的话,则从不匹配的第一个字符开始。 上面每个方法都返回boolean类型,返回true则意味的匹配,返回false则不匹配。 要检测给定的String是否匹配给定的模式,只须下面这样就可以了: Matcher m = Pattern.compile(yourPattern).matcher(yourString); if (m.find()) { System.out.println(“match”); } else { System.out.println(“no match”); }</td> </tr> <tr>
↑返回目录
前一篇: Java虚拟机(JVM)对象创建浅析
后一篇: Java谜题中文版