java程序实现编写代码时变量名垂直对齐的风格

记录英语单词时,想把英语和中文翻译分别对齐,有些人写代码喜欢把变量按这种方式对齐。在网上没搜到相关方法,于是自己试着写代码去实现,原本以为很简单,写的时候才发现有不少问题。先看效果:

普通的

对齐前:

对齐后:

发挥点创意

对齐前:

对齐后:

 

实现

实现的思路比较简单,读取文本文件,按正则分割,找出最长的部分,补齐空格,输出。

看起来相当简单,花了一个多小时,就写出来了,马上运行,发现输出一团糟,去查看每个部分的字符数,个数是一样的,网上一搜,原来跟字体有关系,好吧,那换个等宽的字体。换好字体后有些地方已经对齐了,有些地方还是没对齐,发现是中文的问题,中文宽度与英文宽度不相同,于是首先根据正则去判断字符是中文还是英文,然后自己实现计算字符长度的方法,在判断中文字符上折腾了许久,因为标点符号等等都要考虑进去,反正是来来回回试了好久,对Unicode编码范围不熟悉,没办法。终于,好像都搞定了,反复测试,突然发现第一行的对齐少了一个空格,尼玛,这是怎么回事啊,Debug发现第一行的最开始有一个奇怪的字符"\uFEFF",这他妈是什么鬼,上网搜,发现是Unicode编码的什么BOM头,好吧,不管它是什么鬼,直接把它去掉了……

反正是遇到了各种各样的问题,与字符集相关的问题实在是太头疼了。另外,我没有去处理编码的问题,所以文本的编码需要和IDE的编码保持一致,否则就会产生乱码。

源码

看过《重构》和《代码整洁之道》之后,写代码时时刻想着要写干净点,扩展性强点,经过反复修改,最终自己觉得还行吧,当然,肯定有不少值得改进的地方,现在就这样吧。

 

App.java

 1 package textalign;
 2 
 3 import java.io.IOException;
 4 
 5 /**
 6  * @author tingl
 7  * @version 2017/9/27
 8  */
 9 public class App {
10 
11     public static void main(String[] args) {
12         long start = System.currentTimeMillis();
13 
14         String filePath = "C:\\Users\\tingl\\Desktop\\Test2.txt";
15         TextAlign textAlign = new TextAlign(/*",|。|,|[.]|( {2,})|\t| +"*/);
16 
17         if (args.length > 0) {
18             filePath = args[0];
19         }
20         try {
21             textAlign.align(filePath);
22         } catch (IOException e) {
23             e.printStackTrace();
24         }
25 
26         System.out.println(System.currentTimeMillis() - start);
27     }
28 }

 

TextAlign.java

 1 package textalign;
 2 
 3 import java.io.IOException;
 4 import java.util.List;
 5 import java.util.regex.Pattern;
 6 
 7 /**
 8  * @author tingl
 9  * @version 2017/9/27
10  */
11 public class TextAlign {
12     private static final String CHINESE_CHARACTER = "[\u4e00-\u9fa5]|[\uFE30-\uFFA0]|[\u3000-\u303F]";
13     private static final Pattern CHINESE_CHARACTER_PATTERN = Pattern.compile(CHINESE_CHARACTER);
14     private static final int SEPARATE_SPACE_AMOUNT = 4;
15 
16     private TextAlignFileUtil textAlignFileUtil;
17     private List<String[]> textLines;
18     private int[] longestBlockLengths;
19 
20     public TextAlign() {
21         textAlignFileUtil = new TextAlignFileUtil();
22     }
23 
24     public TextAlign(String spiltRegex) {
25         textAlignFileUtil = new TextAlignFileUtil(spiltRegex);
26     }
27 
28     public void align(String filePath) throws IOException {
29         textLines = textAlignFileUtil.readToList(filePath);
30         initLongestBlockLengths();
31         fillTextLinesBySpaces();
32         textAlignFileUtil.write();
33     }
34 
35     private void initLongestBlockLengths() {
36         int longestArrayLength = 0;
37         for (String[] blocks : textLines) {
38             if (blocks.length > longestArrayLength) {
39                 longestArrayLength = blocks.length;
40             }
41         }
42         longestBlockLengths = new int[longestArrayLength];
43         fillLongestBlockLengths();
44     }
45 
46     private void fillLongestBlockLengths() {
47         for (String[] blocks : textLines) {
48             if (blocks.length < 2) continue;
49             for (int i = 0; i < blocks.length; i++) {
50                 int length = stringLengthFitWidth(blocks[i]);
51                 if (length > longestBlockLengths[i]) {
52                     longestBlockLengths[i] = length;
53                 }
54             }
55         }
56     }
57 
58     private int stringLengthFitWidth(String s) {
59         if (!CHINESE_CHARACTER_PATTERN.matcher(s).find()) {
60             return s.length();
61         }
62         int length = 0;
63         for (String c : s.split("")) {
64             if (CHINESE_CHARACTER_PATTERN.matcher(c).find()) {
65                 length++;
66             }
67             length++;
68         }
69         return length;
70     }
71 
72     private void fillTextLinesBySpaces() {
73         for (String[] blocks : textLines) {
74             for (int i = 0; i < blocks.length - 1; i++) {
75                 String block = blocks[i];
76                 int spaceAmount = longestBlockLengths[i] - stringLengthFitWidth(block) + SEPARATE_SPACE_AMOUNT;
77                 blocks[i] = block + spaces(spaceAmount);
78             }
79         }
80     }
81 
82     private String spaces(int spaceAmount) {
83         StringBuilder spaces = new StringBuilder();
84         for (int i = 0; i < spaceAmount; i++) {
85             spaces.append(" ");
86         }
87         return spaces.toString();
88     }
89 }

 

TextAlignFileUtil.java

 1 package textalign;
 2 
 3 import java.io.*;
 4 import java.util.ArrayList;
 5 import java.util.Arrays;
 6 import java.util.List;
 7 
 8 /**
 9  * @author tingl
10  * @version 2017/9/27
11  */
12 class TextAlignFileUtil {
13     private static final String FILENAME_POSTFIX = "_aligned";
14     private String spiltRegex = "( {2,})|\t";
15     private List<String[]> textLines;
16     private String outPath;
17 
18     TextAlignFileUtil() {
19     }
20 
21     TextAlignFileUtil(String spiltRegex) {
22         this.spiltRegex = spiltRegex;
23     }
24 
25     List<String[]> readToList(String path) throws IOException {
26         File file = new File(path);
27         return readToList(file);
28     }
29 
30     private List<String[]> readToList(File file) throws IOException {
31         getOutPath(file.getAbsolutePath());
32         try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
33             textLines = new ArrayList<>();
34             String line;
35             while ((line = reader.readLine()) != null) {
36                 textLines.add(removeEmptyAndTrim(line.split(spiltRegex)));
37             }
38         }
39         removeBomHead();
40         return textLines;
41     }
42 
43     private void getOutPath(String srcPath) {
44         int dotPosition = srcPath.lastIndexOf(".");
45         outPath = srcPath.substring(0, dotPosition) + FILENAME_POSTFIX + srcPath.substring(dotPosition);
46         if (new File(outPath).exists()) {
47             getOutPath(outPath);
48         }
49     }
50 
51     private String[] removeEmptyAndTrim(String[] src) {
52         for (int i = 0; i < src.length; i++) {
53             src[i] = src[i].trim();
54         }
55 
56         List<String> dest = new ArrayList<>(Arrays.asList(src));
57         dest.removeIf(String::isEmpty);
58         return dest.toArray(new String[0]);
59     }
60 
61     private void removeBomHead() {
62         String[] blocks = textLines.get(0);
63         blocks[0] = blocks[0].replace("\uFEFF", "");
64     }
65 
66     void write() throws IOException {
67         try (BufferedWriter writer = new BufferedWriter(new FileWriter(outPath))) {
68             for (String[] blocks : textLines) {
69                 writer.write(getLine(blocks));
70                 writer.newLine();
71                 writer.flush();
72             }
73         }
74     }
75 
76     private String getLine(String[] blocks) {
77         StringBuilder sb = new StringBuilder();
78         for (String block : blocks) {
79             sb.append(block);
80         }
81         return sb.toString();
82     }
83 }
posted @ 2017-09-28 20:39  changshanfeilong  阅读(755)  评论(1编辑  收藏  举报