3

我有以下类PlaceHolderConverter用于将字符串解析"my {} are beautiful"为带有填充变量的字符串。

例如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();
    }
}

正如您在以下测试中看到的,我对特殊字符美元有疑问,因为它是 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

4

4 回答 4

5

替换固定字符串时,无需调用 String 上的正则表达式方法,因为有一个更简单的方法:input.replace("$", "\\$");. 使用这种方法,您将不会遇到由美元符号的特殊含义引起的任何麻烦,并且它会(非常稍微)更快作为奖励。

于 2012-10-23T13:42:11.550 回答
4

Pattern.quote()失败原因的解释:

Pattern.quote()旨在用于正则表达式(意思是搜索表达式)。它通过用"\\Q"和包围字符串来工作"\\E",分别表示“逐字部分的开始”和“逐字部分的结束”。

您的错误是由替换$字符串中的未转义引起的 ,这不是正则表达式,因此无法使用. 因此,正确的解决方案是在替换字符串中手动转义美元符号:Pattern.quote()

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

或(因为您根本不需要正则表达式来替换单个字符)使用

String resultString = subjectString.replace("$", "\\$");
于 2012-10-23T13:42:30.317 回答
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%

于 2012-10-23T13:31:58.473 回答
0

作为记录,您可以让 Java 以您喜欢的任何替换顺序为您转义 '$' 符号(与其他特殊字符,如 '\' 一样)。这样,如果您愿意,您仍然可以使用 String.replaceAll()。

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

(参见 Java 文档)

于 2017-04-06T19:05:01.967 回答