2016-12-31 34 views
1

我一直在試圖設計一種替換多個String#replaceAll調用模式/匹配器實例的方法,希望它會比我當前的替換字符串中的文本的方法更快,但我不知道如何去做。Java正則表達式字符串#replaceAll替代

這裏是我想要操縱一個字符串的例子:

@[email protected] is a @[email protected] @[email protected] text. 

正如你所看到的,也有與之間3個字符的多個字符@;這將永遠是這樣。如果我想要替換'@ xxx @'的每個實例(其中xxx可以是任何小寫字母或0到9的數字),那麼最有效的方法是什麼?目前我正在存儲一個Map,其中的鍵是'@ xxx @'子字符串,並且這些值是我想要替換該特定子字符串的值;我檢查整個字符串是否包含'@ xxx @'子字符串,併爲每個實例調用replaceAll方法,但我想這是非常低效的。

非常感謝!

TL; DR - 將模式/匹配器替換一個字符串的子字符串與不同的字符串比檢查字符串是否包含子字符串並使用String#replaceAll更有效?如果是這樣,我會怎麼做呢?

+0

「的replaceAll」已經正則表達式;學會使用正則表達式。 –

+0

@BoristheSpider問題不在於如何編寫正則表達式,而是如何使用依賴關鍵字的值替換多個不同的'@ keyword @'模式,而不使用多個'replaceAll()'調用。技巧是['appendReplacement()'](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#appendReplacement-java.lang.StringBuffer-java。 lang.String-)和['appendTail()'](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#appendTail-java.lang.StringBuffer- )'匹配器'的方法。 – Andreas

+0

@Andreas謝謝你,這是一個非常有趣的方式,只需要一次搜索字符串即可。你有使用StringBuffer而不是StringBuilder的原因嗎?另外,如果我有大約50種不同的子字符串可以被替換,它會不會略爲冗長? –

回答

1

這是一個相對簡單的情況下爲appendReplacement

// Prepare map of replacements 
Map<String,String> replacement = new HashMap<>(); 
replacement.put("bla", "hello,"); 
replacement.put("red", "world!"); 
// Use a pattern that matches three [email protected] between two @s 
Pattern p = Pattern.compile("@([^@]{3})@"); 
Matcher m = p.matcher("@[email protected] is a @[email protected] @[email protected] text"); 
StringBuffer sb = new StringBuffer(); 
while (m.find()) { 
    // Group 1 captures what's between the @s 
    String tag = m.group(1); 
    String repString = replacement.get(tag); 
    if (repString == null) { 
     System.err.println("Tag @"+tag+"@ is unexpected."); 
     continue; 
    } 
    // Replacement could have special characters, e.g. '\' 
    // Matcher.quoteReplacement() will deal with them correctly: 
    m.appendReplacement(sb, Matcher.quoteReplacement(repString)); 
} 
m.appendTail(sb); 
String result = sb.toString(); 

Demo.

+0

由於我的字符串在@字符之間只有3個字符,這正是我所要查找的,謝謝! –

3

這是previous answer更加動態版本到另一個類似的問題。

這裏是幫助您搜索任何@[email protected]的方法。它們不一定是3個字符。

private static String replace(String input, Map<String, String> replacement) { 
    StringJoiner regex = new StringJoiner("|", "@(", ")@"); 
    for (String keyword : replacement.keySet()) 
     regex.add(Pattern.quote(keyword)); 
    StringBuffer output = new StringBuffer(); 
    Matcher m = Pattern.compile(regex.toString()).matcher(input); 
    while (m.find()) 
     m.appendReplacement(output, Matcher.quoteReplacement(replacement.get(m.group(1)))); 
    return m.appendTail(output).toString(); 
} 

測試

Map<String,String> replacement = new HashMap<>(); 
replacement.put("bla", "hello,"); 
replacement.put("red", "world!"); 
replacement.put("Hold", "wait"); 
replacement.put("Better", "more"); 
replacement.put("a?b*c", "special regex characters"); 
replacement.put("foo @ bar", "with spaces and the @ boundary character work"); 

System.out.println(replace("@[email protected] is a @[email protected] @[email protected] text", replacement)); 
System.out.println(replace("But @[email protected], this can do @[email protected]!", replacement)); 
System.out.println(replace("It can even handle @a?b*[email protected] without dying", replacement)); 
System.out.println(replace("Keyword @foo @ [email protected] too", replacement)); 

輸出

hello,This is a world!line hello,of text 
But wait, this can do more! 
It can even handle special regex characters without dying 
Keyword with spaces and the @ boundary character work too 
+0

我真的希望我可以同時接受你的答案,因爲他們都足夠了,但是我的子字符串在@符號之間只有3個字符長。不過,我想這將肯定會有助於未來的人,謝謝! –

+1

這很好,特別是使用'Pattern.quote(關鍵字)',這很容易錯過。 – dasblinkenlight

+1

@dasblinkenlight DOH!我忘記了更容易錯過'Matcher.quoteReplacement()'。固定。 ;-) – Andreas