-4

これが私の正規表現です。すべての特殊文字を検索して、それらをエスケープできるようにしています。

(\(|\)|\[|\]|\{|\}|\?|\+|\\|\.|\$|\^|\*|\||\!|\&|\-|\@|\#|\%|\_|\"|\:|\<|\>|\/|\;|\'|\`|\~)

ここでの私の問題は、シーケンスで来るときにのみいくつかの特殊な文字をエスケープしたくないということです

このような(.*)

それでは、例を考えてみましょう。

Sting message = "Hi, Mr.Xyz! Your account number is :- (1234567890) , (,*) &$@%#*(....))(((";

現在の正規表現に従ってエスケープした後、私が得るものは、

Hi, Mr\.Xyz\! Your account number is \:\- \(1234567890\) , \(,\*\) \&\$\@\%\#\*\(\.\.\.\.\)\)\(\(\(

しかし、この部分を逃がしたくないので(.*)、そのままにしておきたいのです。

上記の正規表現は検索にのみ使用されるため、この部分と一致させたくないので(.*)、問題は解決されます

文字列のその部分をエスケープしない正規表現を誰かが提案できますか?

4

2 に答える 2

3

正規表現を使用してこれを行う方法については、@nhahtdhを参照してください。

別の方法として、正規表現を使用せず、代わりにGuavaのCharMatcherを使用するソリューションを次に示します。

private static final CharMatcher SPECIAL
    = CharMatcher.anyOf("allspecialcharshere");
private static final String NO_ESCAPE = "(.*)";

public String doEncode(String input)
{
    StringBuilder sb = new StringBuilder(input.length());

    String tmp = input;

    while (!tmp.isEmpty()) {
        if (tmp.startsWith(NO_ESCAPE)) {
            sb.append(NO_ESCAPE);
            tmp = tmp.substring(NO_ESCAPE.length());
            continue;
        }
        char c = tmp.charAt(0);
        if (SPECIAL.matches(c))
            sb.append('\\');
        sb.append(c);
        tmp = tmp.substring(1);
    }

    return sb.toString();
}
于 2013-01-12T10:04:58.083 に答える
2

この答えは、可能性を示すためだけのものです。本番コードでそれを使用することは疑わしいです。

Java文字列replaceAll関数で可能です:

String input = "Hi, Mr.Xyz! Your account number is :- (1234567890) , (.*) &$@%#*(....))(((";
String output = input.replaceAll("\\G((?:[^()\\[\\]{}?+\\\\.$^*|!&@#%_\":<>/;'`~-]|\\Q(.*)\\E)*+)([()\\[\\]{}?+\\\\.$^*|!&@#%_\":<>/;'`~-])", "$1\\\\$2");

結果:

"Hi, Mr\.Xyz\! Your account number is \:\- \(1234567890\) , (.*) \&\$\@\%\#\*\(\.\.\.\.\)\)\(\(\("

別のテスト:

String input = "(.*) sdfHi test message <> >>>>><<<<f<f<,,,,<> <>(.*) sdf (.*)  sdf (.*)";

結果:

"(.*) sdfHi test message \<\> \>\>\>\>\>\<\<\<\<f\<f\<,,,,\<\> \<\>(.*) sdf (.*)  sdf (.*)"

説明

生の正規表現:

\G((?:[^()\[\]{}?+\\.$^*|!&@#%_":<>/;'`~-]|\Q(.*)\E)*+)([()\[\]{}?+\\.$^*|!&@#%_":<>/;'`~-])

\文字列内で正規表現が指定されている場合はもう一度エスケープ"されるため、エスケープする必要があることに注意してください。結果として得られる文字列の正規表現は上に表示されています。

生の置換文字列:

$1\\$2

置換文字列には特別な意味があり、それを保持$たいので、をエスケープしないようにエスケープする必要があります。また、置換文字列を引用符で囲まれた文字列に入れると、をエスケープするためにの数を2倍にする必要があります。$2\\$\\

モンスターを解剖する前に、アイデアについて話しましょう。特殊文字以外の文字、置き換えたくないシーケンス、および可能な限り多くを消費します。次の文字は、置換したくないシーケンスを形成していない特殊文字であるか、文字列の終わりです(つまり、置換が必要なすべての文字が見つかったということです)。

当然のことながら、任意の文字列は、次のパターンの多くが連続して構成されていると考えることができます。[0 or more (non-special character or special pattern not to be replace)][special character]、および文字列は。で終わり[0 or more (non-special character or special pattern not to be replace)]ます。

replaceAll関数を正規表現なしで使用すると、\G連続していない一致が見つかる可能性があります。これにより、シーケンスの途中で置き換えられないようにカットされ、混乱する可能性があります。\G最後の試合の境界を意味し、最後の試合が中断したところから次の試合が始まることを確認するために使用できます。

  • \G:最後の試合から開始

  • ((?:[^()\[\]{}?+\\.$^*|!&@#%_":<>/;'`~-]|\Q(.\*)\E)*+):0個以上の非特殊文字または置換されない特殊パターンをキャプチャします。+の後に所有格修飾子を追加したことに注意してください*。これにより、この後に指定した特殊文字が見つからない場合にエンジンがバックトラックするのを防ぐことができます。

    • [^()\[\]{}?+\\.$^*|!&@#%_":<>/;'`~-]:特殊文字の否定文字クラス。

    • \Q(.*)\E(.*):置き換えられない特別なシーケンス、文字通りとで引用さ\Q\Eます。

  • ([()\[\]{}?+\\.$^*|!&@#%_":<>/;'`~-]):単一の特殊文字をキャプチャします。

正規表現全体は、最小長が1(特殊文字)の文字列と一致します。最初のキャプチャグループには、置き換えてはならないパーツが含まれ、2番目のキャプチャグループには、置き換えるべき特殊文字が含まれています。

于 2013-01-12T14:29:55.207 に答える