有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

这是我的正则表达式,我正在尝试搜索所有特殊字符,这样我就可以避开它们

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

我这里的问题是,我不想只在序列中出现某些特殊字符时才对其进行转义

像这样(.*)

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

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

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

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

但是,我不想逃避这一部分(.*)我想保持现状

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

有人能建议正则表达式不转义字符串的这一部分吗


共 (2) 个答案

  1. # 1 楼答案

    有关如何使用正则表达式执行此操作,请参见@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();
    }
    
  2. # 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保留它,因此需要转义\,以便\不会转义$。将替换字符串放在带引号的字符串中,需要将\的数量加倍,以转义\

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

    当然,我们可以将任意字符串看作是由以下许多模式连续组成:[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)]结尾

    当不使用^ {< CD14>}的正则表达式时,函数p>^ {CD1>}可以找到不连续的匹配,这可以在序列的中间切去不被替换并使其混乱。{}表示最后一个匹配的边界,可用于确保下一个匹配从最后一个匹配结束的位置开始

    • \G:从上次匹配开始

    • ((?:[^()\[\]{}?+\\.$^*|!&@#%_":<>/;'`~-]|\Q(.\*)\E)*+):捕获0个或多个不被替换的非特殊字符或特殊模式。注意,我在*之后添加了所有格限定符+。这将防止引擎在找不到我们在此之后指定的特殊字符时进行回溯

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

      • \Q(.*)\E:特殊序列(.*)不被替换,文字由\Q\E引用

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

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