1

Java のパターンとマッチャーを使用して複数の文字列置換を実行しようとしています。正規表現パターンにはメタ文字 (\b、() など) が含まれる場合があります。たとえば、入力文字列のfit i am場合、置換を適用したいと思います:

\bi\b --> EYE
i     --> I

次に、2 つの質問 ( Java 文字列内の複数の異なる部分文字列を一度置換する、置換テキストが検索テキストと重複する場合に Java で複数の部分文字列を置換する) のコーディング パターンに従いました。両方で、論理和検索パターン (例: foo|bar) と (パターン、置換) のマップを作成し、matcher.find()ループ内で検索して置換を適用します。

私が抱えている問題は、関数にメタ文字の一致に関する情報が含まれていないため、と をmatcher.group()区別できないことです。以下のコードを参照してください。問題を解決するにはどうすればよいですか?i\bi\b

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

public class ReplacementExample
{
    public static void main(String argv[])
    {
        Map<String, String> replacements = new HashMap<String, String>();
        replacements.put("\\bi\\b", "EYE");
        replacements.put("i", "I");

        String input = "fit i am";

        String result = doit(input, replacements);

        System.out.printf("%s\n", result);
    }


    public static String doit(String input, Map<String, String> replacements)
    {
        String patternString = join(replacements.keySet(), "|");
        Pattern pattern = Pattern.compile(patternString);
        Matcher matcher = pattern.matcher(input);
        StringBuffer resultStringBuffer = new StringBuffer();

        while (matcher.find())
        {
            System.out.printf("match found: %s at start: %d, end: %d\n",
                matcher.group(), matcher.start(), matcher.end());

            String matchedPattern = matcher.group();
            String replaceWith = replacements.get(matchedPattern);

            // Do the replacement here.
            matcher.appendReplacement(resultStringBuffer, replaceWith);
        }

        matcher.appendTail(resultStringBuffer);

        return resultStringBuffer.toString();
    }

    private static String join(Set<String> set, String delimiter)
    {
        StringBuilder sb = new StringBuilder();
        int numElements = set.size();
        int i = 0;

        for (String s : set)
        {
            sb.append(Pattern.quote(s));
            if (i++ < numElements-1) { sb.append(delimiter); }
        }

        return sb.toString();
    }
}

これは出力します:

match found: i at start: 1, end: 2
match found: i at start: 4, end: 5
fIt I am

理想的には、そうあるべきですfIt EYE am

4

2 に答える 2

0

正規表現の1つを間違って入力しました:

    replacements.put("\\bi\\", "EYE"); //Should be \\bi\\b
    replacements.put("i", "I");

また、正規表現を一意にすることもできます。map.getKeySet()での順序の保証はないため、チェックする前にiをIに置き換えている可能性があります\\bi\\b

于 2012-05-15T18:31:45.907 に答える
0

既存の設計から大きく逸脱することなく、キャプチャ グループを使用できます。したがって、一致したパターンをキーとして使用する代わりに、リスト内の順序に基づいて検索します。

次のように、各パターンを括弧で囲むように結合方法を変更する必要があります。

private static String join(Set<String> set, String delimiter) {
    StringBuilder sb = new StringBuilder();
    sb.append("(");
    int numElements = set.size();
    int i = 0;
    for (String s : set) {
        sb.append(s);
        if (i++ < numElements - 1) {
            sb.append(")");
            sb.append(delimiter);
            sb.append("(");         }
    }
    sb.append(")");
    return sb.toString();
}

補足として、元のコード リストで Pattern.quote を使用すると、これらのメタ文字が存在する場所で一致が失敗します。

これを行った後、どのキャプチャ グループが一致を担当したかを判断する必要があります。簡単にするために、一致パターン自体にキャプチャ グループが含まれていないと仮定します。その場合、マッチャーの while ループ内で次のようなものが機能します。

        int index = -1;
        for (int j=1;j<=replacements.size();j++){
            if (matcher.group(j) != null) {
                index = j;
                break;
            }

        }
        if (index >= 0) {
            System.out.printf("Match on index %d = %s %d %d\n", index, matcher.group(index), matcher.start(index), matcher.end(index));
        }

次に、結果のインデックス値を使用して、置換に直接インデックスを付けたいと思います。元のコードは HashMap を使用していますが、これには適していません。リストのペアを何らかの形で使用するには、これをリファクタリングする必要があります。一方には一致パターンのリストが含まれ、もう一方には対応する置換文字列のリストが含まれます。ここでは行いませんが、実用的なソリューションを作成するのに十分な詳細が提供されることを願っています。

于 2012-05-15T22:55:49.397 に答える