实习时昨天写了一整天正则表达式,要匹配多个型号ONU交换机返回的报文数据,测试数据文本文档大小200MB+,共有200万+条数据,由4家厂商的交换机返回数据。
要写正则就要先看数据格式,200MB+的文本文件,NotePad++根本打不开,Sublime Text2打开后电脑变得很慢,根本不可能在Sublime Text里使用正则匹配,数据翻页都卡。就在网上找到了一段分割文本文件的Java代码,感谢 stackoverflow.com 源网址看这里 ,我把代码贴下来。
分割好后,就粘贴了一部分数据开始写正则,基本的思路是,开始匹配一部分,然后使用Java对整个文档进行测试,然后找到不匹配的数据,迭代匹配。
整个过程还是比较痛苦的,在不断发现新的格式问题。最后不得不使用两个正则表达式作匹配,因为有些厂商在做报文的时候,格式并不统一:
- 字段之间的分隔,有些厂商是以Tab空白符分割,有些厂商是以2个或更多Space空白符分割;
- 字段内部,有些厂商是以“-”连接字段内的各部分,组成整个字段,有些厂商字段内部使用了单个Space空白符;
- 字段个数,大部分厂商是返回的报文有12个字段,但是某商的某部分型号交换机,返回的是……11个字段,同时使用了2个Space空白符分割字段,字段内部使用单个Space空白符。
像3那样的返回数据很难分辨出到底是含有多少字段,某商……加油。我是在解决了1和2的问题之后,发现还有一些无法匹配的字段,仔细比对数据之后才发现只有11个字段。在解决1和2的过程中,发现由于分割符的区别,不可能只使用 “s” 实现所有数据的字段分隔:
- 字段间以Tab分隔的报文格式,则以 “ ” 分隔各个字段,为了匹配字段内部的Space空白符,使用 ` [Ss]*? `规则,这个规则是在两个Tab符之间,使用懒惰原则匹配出任意字符与任意空白符的字符串;
- 字段间以2个或更多Space分隔的报文格式,根据Space空白符出现的次数进行分隔,规则是 `s{2,}`,匹配字段内部的Space空白符,思路同1,规则更改为`s{2,}[Ss]*?s{2,}`;
- 部分只有11个字段的报文数据,是#2的子集,因此寻找方法修改#2的匹配规则,好在缺失的报文是同一列,举例说明缺失的字段为“A B C”中间的B字段,A与C之间在缺失B时,使用了4个Space空白符进行分隔。解决方案:在匹配到A字段后,放弃`s{2,}S+s{2,}`规则,而改为`s{2}[Ss]*?s{1,}`,即A字段后匹配到2个空白符,接着使用懒惰匹配,在2个空白字符与至少1个空白字符之间,匹配任意非空白字符与空白字符组合的字符串。举例说明更好一点:
#1 正常字段数(字段以2空格符分割) A B C adkc kdlsk kslakd #2 缺少字段B数据(字段以4空格符分割) A C adkc kslakd 匹配规则 S+s{2}([Ss]*?)s{1,}S+ S+会匹配到字段A,s{2}会匹配到字段A后的2个空格字符,[Ss]*?是懒惰 匹配非空白字符与空白字符混合任意次,直到遇到“最少一个空白符字段”,即s{1,}所表示规则,此时#1会匹配到B字段,#2会匹配到空字符,因为在2个空白符之后,还是跟着空格符。S+匹配到C字段。
Java分割文本文件源代码:
import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class TextFileSplit { public static void main(String[] args) { if (args.length != 2) { System.out.println("Invalid Input!"); } //第一个参数是文件路径 File file = new File(args[0]); //第二个参数是每个文件的行数 int numLinesPerChunk = Integer.parseInt(args[1])/; BufferedReader reader = null; PrintWriter writer = null; try { reader = new BufferedReader(new FileReader(file)); } catch (FileNotFoundException e) { e.printStackTrace(); } String line; long start = System.currentTimeMillis(); try { line = reader.readLine(); for (int i = 1; line != null; i++) { writer = new PrintWriter(new FileWriter(args[0] + "_part" + i + ".txt")); for (int j = 0; j < numLinesPerChunk && line != null; j++) { writer.println(line); line = reader.readLine(); } writer.flush(); } } catch (IOException e) { e.printStackTrace(); } writer.close(); long end = System.currentTimeMillis(); System.out.println("Taken time[sec]:"); System.out.println((end - start) / 1000); } }