一道文本處理題目的思考

 在網上碰到有網友問了這麼一道題,題目是這樣的:
 
java 寫入txt文件,想要修改txt文件每一行的第一個數字,加1;
例如txt文件是:
1     1     5
2     2     10
3     3     15
 
轉變成:
2     1     5
3     2     10
4     3     15
 
看到題目的第一反應時可能須要正則表達式,而在java中使用raplaceAll("正則表達式","替換後的表達式")基本上就能夠搞定了。可是有一個問題:正則匹配很好寫,reg = "^\\d+";就能夠匹配每行的第一個數字了,可是替換成什麼呢?須要對每一個數字加1,這個怎麼處理?使用捕獲組能夠獲取咱們須要處理的數據,可是捕獲後,沒法進一步處理數據了。此條路不通以後,很不情願的想起另一種辦法:按行處理。
 
掃描須要處理的文本,每掃描一行,就對該行進行匹配,匹配到數據以後,對該行處理,而後將該行寫入到新的文件,整個文本掃描完成以後,數據也就處理完了。這個辦法是否是很笨拙?對於目前也沒有更好的方式(更好的方式也許可使用excel來處理,可是要求使用編程來完成),就開始代碼實現了:
 
// code version 1.0
 
開始寫代碼時,發現數據之間都是以多個空格或者tab來分割,方便期間,使用split函數來處理吧。
 
     // java 解析文本,將每行第一個數字加1
      public  static  void  writeFile() {
           BufferedReader reader =  null ;
           BufferedWriter writer =  null ;
             try {
                File file =  new  File(  "new.txt" );
                  if (!file.exists()) {
                     file.createNewFile();
                }
                StringBuffer sb =  new  StringBuffer();
                reader =  new  BufferedReader(  new  FileReader( "test.txt" ));
                String line =  null ;
                  //按行讀取
                  while ((line = reader.readLine()) !=  null ) {
                     String[] arr = line.split(  "[ \t]++" );
                       if (arr.  length  < 3) {
                           sb.append(line).append(  "\r\n" );
                             continue ;
                     }
                       //獲取第一個數字,並加1
                       int  num = Integer. valueOf(arr[0]);
                     num ++;
                     sb.append(num).append(  "\t" ).append(arr[1]).append(  "\t" ).append(arr[2]).append(  "\r\n" );
                }
                
                  //寫入新的文件
                writer =  new  BufferedWriter(  new  FileWriter(file));
                writer.write(sb.toString());
                
           }  catch  (IOException e) {
                e.printStackTrace();
           }  finally  {
                  if (reader !=  null ) {
                       try  {
                           reader.close();
                     }  catch  (IOException e) {
                             //  TODO  Auto-generated catch block
                           e.printStackTrace();
                     }
                }
                  if (writer !=  null ) {
                       try  {
                           writer.close();
                     }  catch  (IOException e) {
                             //  TODO  Auto-generated catch block
                           e.printStackTrace();
                     }
                }
           }
           
     }
 
代碼寫起來仍是很順利的,可是有個問題,在數據處理完成以後:
int  num = Integer.valueOf(arr[0]);
num ++;
怎麼把新的內容寫入到當前行中,也就是寫入當前的文本中?處理數據的時候是經過reader來按行讀取,若是須要將數據寫入的話,須要writer,在讀取文件的時候,直接使用writer寫入數據,也不是件很容易的事。爲了方便處理,果斷創建一個新的文件,寫入新的數據,處理完以後,刪掉舊的文件就是!
 
代碼實現以後,就跟一個朋友商討了下,朋友說,可使用正則來完成,split的效率有點低。OK,把主要的處理過程從新實現了下:
// code version 1.1
             Pattern pattern = Pattern. compile( "^\\d+"  );
            while(...) {
                Matcher matcher = pattern .matcher(line);
                if (matcher.find()) {
                     String str = matcher.group();
                      int  n = Integer.parseInt(str);
                     n ++;
                     line = line.replaceFirst(str, String.valueOf(n));
                     sb.append(line).append(  "\r\n" );
               }
             }     
 
除了將split修改成Pattern以後,同時,行數據也保持原來的風格保持了不變:
line = line.replaceFirst(str, String. valueOf (n));
 
可是爲何Pattern會比split的效率高呢?
split的實現中,會調用Pattern.compile("...");也就是在對文本每行的處理中,若是使用split,則每次都會新建一個Pattern.compile("...")對象。而在使用Pattern類,只在最開始生成一個Pattern.compile("...")對象,減小了內存的開銷;
 
 
一個前輩說,不須要正則,使用indexOf和substring能夠提升效率。同時,他建議不要使用BufferedWriter,應當使用printStream。
恩,開始修改代碼:
 
// code version 1.2
 
       public   static   void  writeFile()  throws  IOException {
                 BufferedReader reader =  null ;
                 PrintStream writer =  null ;
            
                File file =  new  File(  "new.txt" );
                  if (!file.exists()) {
                     file.createNewFile();
                }
                writer =  new  PrintStream(  new  FileOutputStream(file));
                reader =  new  BufferedReader(  new  FileReader( "test.txt"  ));
                String line =  null ;
                  //按行讀取
                  while ((line = reader.readLine()) !=  null ) {
                       //這裏經過index來肯定須要處理的數據
                       int  index = line.indexOf(  " " );
                       if (index == -1) {
                             continue ;
                      }
                       int  num = Integer.parseInt(line.substring(0,index))+1;
                      line = num + line.substring(index);
                      writer.println(line);
                }
               // ....
           
     }
 
使用indexOf和substring 替換掉正則以後,邏輯彷佛也清晰了許多,因爲去掉了正則表達式的一些處理,直接對字符串處理,效率上應該會有一些提升。可是使用PrintStream 替換掉 BufferedWriter是否是就是個好主意?不見得,BufferedWriter做爲一個具備緩衝功能的包裝類,性能上比其餘類要高不少。並且在處理文本時,每處理一行,就向文件中寫入數據,這個性能也不見得很高。權衡之際,提升處理數據效率,使用indexOf和substring,寫文件時,採用BufferedWriter將數據寫入緩衝,提升效率。
 
// code version 1.3
 
       public   static   void  writeFile()  throws  IOException {
                 BufferedReader reader =  null ;
                 BufferedWriter writer =  null ;
            
                writer =  new  BufferedWriter(  new  FileWriter( "new.txt"  ));
                reader =  new  BufferedReader(  new  FileReader( "test.txt"  ));
                String line =  null ;
                  //按行讀取
                  while ((line = reader.readLine()) !=  null ) {
                       //這裏經過index來肯定須要處理的數據
                      int  index = line.indexOf(  " " );
                      if (index == -1) {
                             continue ;
                     }
                      int  num = Integer.parseInt(line.substring(0,index))+1;
                     line = num + line.substring(index);
                     writer.write(line);
                     writer.newLine();
                }
                
                //...
     }
 
到此,關於該題目的編碼總算塵埃落定。期間,經歷了幾番波折,從split->Pattern->indexOf再到流的選取,糾結了較長時間。總結一下:
 
一、儘可能不要使用正則表達式,可使用indexOf和substring來代替正則;必須使用正則的狀況下,使用Pattern類可以提升效率。
二、使用Buffer之類的包裝類,能夠提升效率。
 
可是,仍是有幾個問題留做之後慢慢考慮吧。
一、直接使用正則或者是否還有其餘更簡單的處理方式麼?
二、如何直接寫入到當前的文件中?
相關文章
相關標籤/搜索