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 );
    }

}

また、ドルを正規表現で使用する前に手動でエスケープしようとしましたが、arg2 に arg1 を含める必要があるのは嫌いなようです.replaceAll("\\$", "\\\\$")replaceAll

どうすれば修正できますか?

パッチはここで提供できます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 に答える