zoukankan      html  css  js  c++  java
  • 文件对比与差异提取的实现

    File Comparison Tool

     

    前言

      一款需要多国语言的应用(真正受欢迎的至少需要中文和英文,不管是PC端还是移动端),那么应用程序开发过程中定义的字串文件就需要进行翻译,而这项工作在大公司往往是多人(甚至是多部门)协同完成。比如移动端开发常见的为strings.xml,默认是在res/values目录下,严格来说该目录对应的是英文环境,而中文简体环境规范的目录为res/values-zh-rCH。

     

    需求

      那么问题来了,开发人员定义好应用中需要用到的字串(最初可能是英文,也可能是中文)并且送翻(提交给专门的翻译人员进行字串翻译)后,怎么判断返回的翻译结果是完整的呢?或者说,中途接手一个项目,怎么快速掌握原来的字串翻译情况呢?

      之前有篇文章讲过Lint工具可以分析出项目中资源冗余及翻译不全等问题,但给出的信息不够简洁,用其来完成专门的字串翻译文件对比并不是很合适。通过下图可以看出,对于某一条字串的翻译缺失,Lint给出的信息是什么样的。

      协同工作的好处是,项目文件的commit、pull、push及review均可以在项目管理工具或者工具对应的命令行环境中进行。而review还可以在项目对应的远程网页中进行,便于管理者查看新提交的文件到底进行了哪些改动。但是其和文件比较工具(如beyond compare)类似,只能一个一个文件地查看,若想提取出所有的修改结果(或者不同点),只能认为地复制与黏贴到自己建立的文件中。

      所以,若想以最初的strings.xml为基础,查看其它语言环境的翻译情况,并将未翻译的字串统一写入到一个特定的文件中,就需要自己进行实现了。

     

    实现

      用来实现该功能的语言平台为Eclipse中的Java,过程大致可以分为四步:

      1、  以项目res目录为起始路径,获取其中包含的所有子文件夹;

      2、  在1的基础上,获取名称中包含values的文件夹,因为其他文件夹和strings.xml无关(当然,这是一般而言的);

      3、  在2的基础上,获取存在的strings.xml的完整路径;

      4、  文件内容对比,针对最初的strings.xml文件中的某一条字串(需要翻译的,即不包括文件定义头<?xml ... ?>、<resources>…</resources>及显示说明不需翻译的字串等),若其他语言环境对应的strings.xml文件中不存在该字串的翻译,那么就将该字串的行号和内容写入结果文件。为了方便阅读和修改,结果是以文件为单位,而不是像Lint工具那样以字串为单位,即原来是某条字串未进行翻译的国家有A、B、C、D、……,而现在是某个语言环境未翻译的字串有A、B、C、D、……;

      完整的Java实现代码如下:

      1 package com.filediff;
      2 
      3 import java.awt.image.WritableRaster;
      4 import java.io.BufferedReader;
      5 import java.io.File;
      6 import java.io.FileNotFoundException;
      7 import java.io.FileReader;
      8 import java.io.FileWriter;
      9 import java.io.IOException;
     10 import java.io.Writer;
     11 import java.time.chrono.JapaneseChronology;
     12 import java.util.ArrayList;
     13 import java.util.Date;
     14 
     15 import javax.swing.JFrame;
     16 
     17 @SuppressWarnings("serial")
     18 public class FileDiff extends JFrame {
     19 
     20     //resources root path
     21     private static String rootDir = "res";
     22     //directory name values
     23     private static String dirFilter = "values";
     24     //file name
     25     private static String fileName = "strings.xml";
     26     //all directory in rootDir
     27     private static String[] subDirs = null;
     28     //all directory(name contain values) in rootDir
     29     private static ArrayList<String> valuesDirs = new ArrayList<String>();
     30     //all file full names as strings.xml
     31     private static ArrayList<String> fileFullNames = new ArrayList<String>();
     32     //result file name
     33     private static String result = "Result.xml";
     34     private static int fileCounts = 0;
     35     private static int fileIndex = 0;
     36     private static String indicate = "name=";
     37     
     38     private static String preDate = new Date().toString()+"
    
    ";
     39 
     40     public static void main(String[] args) throws FileNotFoundException {
     41         getSubDirs();
     42         getValuesDirs();
     43         getfileFullNames();
     44         
     45         fileCounts = fileFullNames.size();
     46         
     47         //打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
     48         FileWriter writer;
     49         try {
     50             writer = new FileWriter(result);
     51             writer.write(preDate);
     52             writer.write("与"+fileFullNames.get(0)+"相比, ");
     53             writer.close();
     54         } catch (IOException e) {
     55             // TODO Auto-generated catch block
     56             e.printStackTrace();
     57         }
     58         //fileCounts
     59         for(fileIndex=1;fileIndex<fileCounts;++fileIndex){
     60             compareFiles();
     61         }
     62     }
     63     
     64     private static void compareFiles(){
     65         FileWriter writer;
     66         try {
     67             writer = new FileWriter(result, true);
     68             String preContent2 = "
    
    "+fileFullNames.get(fileIndex)+"未翻译的字串为: 
    ";
     69             writer.write(preContent2);
     70             
     71             File fileSrc = new File(fileFullNames.get(0));
     72             File fileDes = new File(fileFullNames.get(fileIndex));
     73             BufferedReader readerSrc = null;
     74             BufferedReader readerDes = null;
     75             try {
     76                 readerSrc = new BufferedReader(new FileReader(fileSrc));
     77                 String stringSrc = null;
     78                 String stringDes = null;
     79                 boolean contantFlag = false;
     80                 int line = 1;
     81                 // 一次读入一行,直到读入null为文件结束
     82                 while ((stringSrc = readerSrc.readLine()) != null) {
     83                     if(stringSrc.contains(indicate) && !stringSrc.contains("translatable="false"")){
     84                         String str1 = stringSrc.substring(stringSrc.indexOf("=")+2);
     85                         String str2 = str1.substring(0,str1.indexOf("""));
     86                         readerDes = new BufferedReader(new FileReader(fileDes));
     87                         contantFlag = false;
     88                         while ((stringDes = readerDes.readLine()) != null) {
     89                             if(stringDes.contains(str2)){
     90                                 contantFlag = true;
     91                                 break;
     92                             }
     93                         }
     94                         if (!contantFlag) {
     95                             writer.write("Line number and content is: "+line+", "+stringSrc+"
    ");
     96                         }
     97                     }
     98                     line++;
     99                 }
    100                 readerSrc.close();
    101             } catch (IOException e) {
    102                 e.printStackTrace();
    103             } finally {
    104                 if (readerSrc != null) {
    105                     try {
    106                         readerSrc.close();
    107                     } catch (IOException e1) {
    108                     }
    109                 }
    110             }
    111                         
    112             writer.close();
    113         } catch (IOException e) {
    114             // TODO Auto-generated catch block
    115             e.printStackTrace();
    116         }
    117     }
    118     
    119     //get all directory in rootDir
    120     private static void getSubDirs(){
    121         File fileDirRoot = new File(rootDir);
    122         subDirs = fileDirRoot.list();
    123     }
    124     
    125     //get all directory(name contain values) in rootDir
    126     private static void getValuesDirs(){
    127         for(int i=0;i<subDirs.length;++i){
    128             if(subDirs[i].contains(dirFilter)){
    129                 valuesDirs.add(subDirs[i]);
    130             }
    131         }
    132     }
    133     
    134     //get all fileFullNames(contain strings.xml) in rootDir
    135     private static void getfileFullNames(){
    136         for(int i=0;i<valuesDirs.size();++i){
    137             File file = new File(rootDir+"\"+valuesDirs.get(i)+"\"+fileName);
    138             if(file.exists()){
    139                 fileFullNames.add(rootDir+"\"+valuesDirs.get(i)+"\"+fileName);
    140             }
    141         }
    142     }
    143 }

      从代码可以看出,以上描述的四个步骤对应的方法分别为getSubDirs()、getValuesDirs()、getfileFullNames()、compareFiles()。

      在结果文件Result.xml的开头,写入了当前时间,其对应字串的获取方式为:new Date().toString()。

      注意,如代码138-140行所示,在将某个语言环境对应的strings.xml文件完整名称添加入ArrayList对象fileFullNames中之前,对其存在性进行了判断,也可以在后面的文件比较环节进行个文件的存在性判断,但不能不判断就进行文件的读取(多余,也容易引起异常)。

      res目录下的文件夹获取情况:

      res目录下的名称中包含values的文件夹获取情况:

      res目录下的名称中包含values的文件夹中strings.xml的完整名称获取情况:

      所有翻译字串最终的对比结果文件Result.xml的部分内容为:

       有了这样的描述,就很容易查看当前多国语言的翻译情况了。这里的字串是随意敲的,不然命名的level也太低了。

     

    总结

      虽然实现的功能具有局限性,但已经可以满足上面的需求。正是因为一般通用的工具不能完成项目开发过程中遇到的所有情况,所以才要自己动手针对特定的需求进行实现。这篇文章只是起到抛砖引玉的作用,对于其他各种各样的场景,实现的思路还是相同的。

      欢迎感兴趣的朋友一起讨论、学习与进步!

  • 相关阅读:
    杨辉三角1
    岛屿与周长
    什么是计算机语言
    爬虫爬取视图片
    爬虫爬取文字生成词云
    英文词频统计
    回溯法~0-1背包的实现
    java Swing图形化界面
    棋盘覆盖
    敏捷软件开发 10~12章
  • 原文地址:https://www.cnblogs.com/tgyf/p/4754547.html
Copyright © 2011-2022 走看看