2012-10-23 26 views
2

我有以下類PlaceHolderConverter用於將字符串如"my {} are beautiful"解析爲具有填充變量的字符串。在java正則表達式中處理美元字符的最佳方法

例如new PlaceHolderConverter("\\{\\}").format("my {} are beautiful", "flowers")將返回字符串"my flowers are beautiful"

package something; 


import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class PlaceHolderConverter 
{ 
    public Pattern lookForVar; 

    public PlaceHolderConverter(String placeHolder) 
    { 
     this.lookForVar = Pattern.compile(placeHolder); 
    } 

    public String format(String text, String... args) 
    { 
     if (args == null || args.length == 0) 
     { 
      return text; 
     } 
     StringBuffer stringBuffer = new StringBuffer(); 
     Matcher matcher = lookForVar.matcher(text); 
     short varCount = 0; 
     while (matcher.find()) 
     { 
      matcher.appendReplacement(stringBuffer, args[varCount++]); 
     } 
     matcher.appendTail(stringBuffer); 
     return stringBuffer.toString(); 
    } 
} 

正如你在下面的測試中看到的,我對特殊字符dollar有問題,因爲它是java正則表達式的特殊字符。 我試圖用Pattern.quote()來解決這個問題,但沒有結果。

package something; 

import org.junit.Assert; 
import org.junit.Before; 
import org.junit.Test; 

import java.util.regex.Pattern; 

public class PlaceHolderConverterTest 
{ 
    private PlaceHolderConverter placeHolderConverter; 

    @Before 
    public void before() 
    { 
     placeHolderConverter = new PlaceHolderConverter("\\{\\}"); 
    } 

    @Test // SUCCESS 
    public void whenStringArgsThenReplace() 
    { 
     String result = placeHolderConverter.format("My {} are beautifull", "flowers"); 
     Assert.assertEquals("My flowers are beautifull", result); 
    } 

    @Test // FAIL IllegalArgumentException illegal group reference while calling appendReplacement 
    public void assertEscapeDollar() 
    { 
     String result = placeHolderConverter.format("My {} are beautiful", "flow$ers"); 
     Assert.assertEquals("My flow$ers are beautiful", result); 
    } 

    @Test // FAIL IllegalArgumentException illegal group reference while calling appendReplacement 
    public void assertEscapeDollarWithQuote() 
    { 
     String result = placeHolderConverter.format("My {} are beautiful", Pattern.quote("flow$ers")); 
     Assert.assertEquals("My flow$ers are beautiful", result); 
    } 

} 

我也試過正則表達式中使用它,喜歡的東西.replaceAll("\\$", "\\\\$")之前,需要手動逃離美元,但似乎不喜歡replaceAll不得不ARG1列入ARG2。

我該如何解決這個問題?

補丁可以在這裏提供https://gist.github.com/3937872

+3

使用簡單的'replace'功能,以取代固定的字符串:'s.replace( 「$」, 「\\ $」);' –

+0

而當串有多個塊錢? – tbruyelle

+0

一個電話就夠了。查看Javadoc並嘗試一下。 –

回答

4

當替換固定字符串時,不需要在字符串上調用正則表達式方法,因爲有一個簡單的方法:input.replace("$", "\\$");。使用這種方法,您不會遇到任何由美元符號的特殊含義所引起的麻煩,並且它將作爲獎金(非常輕微)更快。

2

下面是簡單的解決方案,它涵蓋你的測試用例:

public static String replace(String str, String placeholderRegex, Object... args) { 
    String repl = str.replaceAll(placeholderRegex, "%s"); 
    return String.format(repl, args); 
} 

讓我們檢查一下:

public static void main(String[] args) { 
    System.out.println( 
      replace("my {} are beautifull {} test", 
        "\\{\\}", 
        "flowers", "$dollar")); 
} 

但是,當然,如果你必須處理%個字符,您必須修改功能replace有點(在更換之前轉義% t和unescape之後)。你也可以使用預編譯的正則表達式(如你的解決方案)。

+1

該死的你剛纔把我的代碼行分成了5個好的提示,用'「%s」代替placeHolder' – tbruyelle

3

爲什麼Pattern.quote()失敗的解釋:

Pattern.quote()被設計爲正則表達式使用(這意味着搜索表達式)。它的工作原理是分別用"\\Q""\\E"圍繞字符串,即「逐字節開始」和「逐字節結束」。從轉義$

你的錯誤會導致你的更換字符串,它不是一個正則表達式,因此不能正確轉義使用Pattern.quote()。因此,正確的解決方法是手動逃離美元符號的替換字符串:使用

String resultString = subjectString.replace("$", "\\$"); 
0

String resultString = subjectString.replaceAll("\\$", "\\\\\\$"); 

或者(因爲你並不需要一個正則表達式在所有的單個字符替換)爲了記錄,您可以讓Java在任何替換序列中爲您(如其他特殊字符,如'\')轉義'$'標誌。如果你願意,這樣你仍然可以使用String.replaceAll()。

String s = "input".replaceAll("pattern", Matcher.quoteReplacement("replacement")); 

(See Java Doc)

相關問題