場景:
配置文件config.properties
配置項cfg.regexp=\d+\t
加載配置文件代碼
InputStream ins = PropManager.class.getResourceAsStream("/config.properties");
prop.load(ins);
現象:
打印cfg.regexp的值輸出為"d+ ",而不是期望的"\d+\t"
原因:
看了下代碼,發現Properties類對'\'做了轉義處理,而且只處理'\uxxxx', '\t','\n','\r','\f'這幾種情況,對於其他情況,就簡單的把'\'吞掉了
1 while (off < end) { 2 aChar = in[off++]; 3 if (aChar == '\\') { 4 aChar = in[off++]; 5 if(aChar == 'u') { 6 // Read the xxxx
7 int value=0; 8 for (int i=0; i<4; i++) { 9 aChar = in[off++]; 10 switch (aChar) { 11 case '0': case '1': case '2': case '3': case '4': 12 case '5': case '6': case '7': case '8': case '9': 13 value = (value << 4) + aChar - '0'; 14 break; 15 case 'a': case 'b': case 'c': 16 case 'd': case 'e': case 'f': 17 value = (value << 4) + 10 + aChar - 'a'; 18 break; 19 case 'A': case 'B': case 'C': 20 case 'D': case 'E': case 'F': 21 value = (value << 4) + 10 + aChar - 'A'; 22 break; 23 default: 24 throw new IllegalArgumentException( 25 "Malformed \\uxxxx encoding."); 26 } 27 } 28 out[outLen++] = (char)value; 29 } else { 30 if (aChar == 't') aChar = '\t'; 31 else if (aChar == 'r') aChar = '\r'; 32 else if (aChar == 'n') aChar = '\n'; 33 else if (aChar == 'f') aChar = '\f'; 34 out[outLen++] = aChar; 35 } 36 } else { 37 out[outLen++] = (char)aChar; 38 } 39 }
解決方法:
我的解決方法是,自己寫個簡單的解析
約定
- 每行第一次出現的'='作為分割符(Properties類可以支持key:value格式)
- key和value都忽略前后空白字符
- 不對字符串做轉義
1 while((line = buffReader.readLine())!=null){ 2 line = line.trim(); 3 if(line.startsWith("#") || line.equals("")){// 忽略#開頭的注釋
4 continue; 5 } 6
7 int index = line.indexOf('='); 8 if(index <= 0){ 9 logger.error("********錯誤的配置文件格式!********line = " + line); 10 continue; 11 } 12 String key = line.substring(0, index).trim(); 13 String value = (index+1>=line.length()) ? "":line.substring(index+1).trim();// 避免越界
14 prop.put(key, value); 15 }
之所以把它記下來是因為我跟同事說起這個現象的時候,同事發現他之前寫的代碼用過類似的正則表達式配置方式,正則表達式里面希望匹配絕對的'\.',而經過Properties類轉義之后變成了'.',意義就變成了“任意字符”,由於運行並不報錯,而且某系情況下結果還是正確的,於是一個潛在的bug就出現了