2012-12-26 56 views
6

目前我使用org.apache.commons.lang.text.StrSubstitutor做JRE庫:StrSubstitutor置換

Map m = ... 
substitutor = new StrSubstitutor(m); 

result = substitutor.replace(input); 

鑑於我想刪除我的項目commons-lang依賴你會使用標準的JRE是一個工作和簡約實施StrSubstitutor事實庫?

注意

StrSubstitutor是這樣工作的:

Map map = new HashMap(); 
map.put("animal", "quick brown fox"); 
map.put("target", "lazy dog"); 
StrSubstitutor sub = new StrSubstitutor(map); 
String resolvedString = sub.replace("The ${animal} jumped over the ${target}."); 

產生resolvedString = 「敏捷的棕色狐狸跳過了懶狗」。

+0

圖書館簡化你的代碼,你爲什麼要刪除依賴? – hoaz

+3

似乎是一個簡單的循環遍歷entrySet,並調用'inputString.replace(「$ {」+ key +「}」,value);'會做伎倆(可能不是最有效的方式)。或者把你需要的代碼從commons-lang ... – assylias

+0

那麼問題是什麼? –

回答

9

的如果性能是不是一個優先事項, 可以使用appendReplacement method of the Matcher class

public class StrSubstitutor { 
    private Map<String, String> map; 
    private static final Pattern p = Pattern.compile("\\$\\{(.+?)\\}"); 

    public StrSubstitutor(Map<String, String> map) { 
     this.map = map; 
    } 

    public String replace(String str) { 
     Matcher m = p.matcher(str); 
     StringBuilder sb = new StringBuilder(); 
     while (m.find()) { 
      String var = m.group(1); 
      String replacement = map.get(var); 
      m.appendReplacement(sb, replacement); 
     } 
     m.appendTail(sb); 
     return sb.toString(); 
    } 
} 

更高性能,但不太美觀的版本,只是爲了好玩:)

public String replace(String str) { 
     StringBuilder sb = new StringBuilder(); 
     char[] strArray = str.toCharArray(); 
     int i = 0; 
     while (i < strArray.length - 1) { 
      if (strArray[i] == '$' && strArray[i + 1] == '{') { 
       i = i + 2; 
       int begin = i; 
       while (strArray[i] != '}') ++i; 
       sb.append(map.get(str.substring(begin, i++))); 
      } else { 
       sb.append(strArray[i]); 
       ++i; 
      } 
     } 
     if (i < strArray.length) sb.append(strArray[i]); 
     return sb.toString(); 
    } 

它大約是正則表達式版本的2倍,比我的測試的Apache公共版本快3倍。所以普通的正則表達式實際上比apache版本更優化。通常當然不值得。只是爲了好玩,讓我知道你是否可以讓它更優化。

編輯:正如@kmek指出的那樣,有一個警告。 Apache版本將以傳遞方式解析。例如,如果${animal}映射到${dog}並且dog映射到Golden Retriever,則apache版本將將${animal}映射到Golden Retriever。正如我所說,你應該儘可能地使用圖書館。上述解決方案只有在您有一個不允許使用庫的特殊約束條件時纔會使用。

+0

,它看起來並不糟糕。爲什麼你認爲這不應該是最佳的表演?我發現它很漂亮! –

+0

'Pattern p = Pattern.compile(「\\ $ \\ {(。+?)\\}」);'可以移動並初始化爲字段;不可以嗎? –

+2

那麼,爲了獲得超級性能,你可以在不使用正則表達式的情況下編寫它 - 你可以通過char來掃描它,使用緩衝區等。是的,你可以使'Pattern'靜態。我會作出這樣的變化.. –

1

在JRE中沒有這樣的東西,但是寫一個很簡單。

Pattern p = Pattern.compile("${([a-zA-Z]+)}"; 
Matcher m = p.matcher(inputString); 
int lastEnd = -1; 
while (m.find(lastEnd+1)) { 
    int startIndex = m.start(); 
    String varName = m.group(1); 
    //lookup value in map and substitute 
    inputString = inputString.substring(0,m.start())+replacement+inputString.substring(m.end()); 
    lastEnt = m.start() + replacement.size(); 
} 

這當然是很沒效率的,你可能應該把結果寫入到一個StringBuilder而不是更換inputString所有的時間

+2

在Java中,如果您使用正則表達式模式,則可以使用String的replaceAll方法。 – JoshDM

+1

因爲你不需要不斷地爲每個變量編譯新的表達式,所以使用Pattern的第一個效率稍高一些。第二,如果我想使用StringBuilder寫輸出以提高效率,我需要在第一眼掃描字符串 – radai