-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 StringreplaceAll函数是可能的:

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,因此您需要转义 ,\这样\就不会转义$. 并将替换字符串放在带引号的字符串中,您需要\\.

在我们剖析怪物之前,让我们谈谈这个想法。我们将使用非特殊字符,以及我们不想替换的序列,并且尽可能多地使用。下一个字符要么是不构成我们不想替换的序列的特殊字符,要么是字符串的结尾(这意味着我们已经找到了所有需要替换的字符(如果有的话))。

自然,我们可以将任意字符串视为由以下许多连续模式组成:[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: 特殊序列(.*)不被替换,字面由\Qand引用\E

  • ([()\[\]{}?+\\.$^*|!&@#%_":<>/;'`~-]):捕获单个特殊字符。

整个正则表达式将匹配最小长度为 1(特殊字符)的字符串。第一个捕获组包含不应替换的部分,第二个捕获组包含应替换的特殊字符。

于 2013-01-12T14:29:55.207 回答