与此字符序列不匹配的正则表达式

时间:2013-01-12 08:05:29

标签: java regex

这是我的正则表达式,我正在尝试搜索所有特殊字符,以便我可以逃脱它们。

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

我的问题是,我不想只是在序列中出现时才会逃避某些特殊字符

喜欢这个(.*)

所以,让我们考虑一个例子。

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

根据当前的正则表达式逃脱后,我得到的是,

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

但是不想逃避这部分(.*)希望保持原样。

我的上述正则表达式仅用于搜索,所以我只是不想与此部分(.*)匹配,我的问题将得到解决

任何人都可以建议没有逃避字符串那部分的正则表达式吗?

2 个答案:

答案 0 :(得分: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();
}

答案 1 :(得分:2)

这个答案只是为了证明这种可能性。在生产代码中使用它是值得怀疑的。

可以使用Java String 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,因此您需要转义\以便\ 1}}不会逃脱$。将替换字符串放在带引号的字符串中,您需要将\的数量加倍以逃避\

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

当然,我们可以认为任意字符串连续由以下许多模式组成:[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的字符串(特殊字符)。第一个捕获组包含不应替换的部分,第二个捕获组包含应替换的特殊字符。