【问题标题】:Swap escaped characters交换转义字符
【发布时间】:2020-10-29 16:16:22
【问题描述】:

我正在尝试交换字符串A * (B + C) / D 中的括号,但交换它们会导致A * \)B + C( / D 而不是A * )B + C( / D

public class InfixToPrefixExpression {
        private String swapStrings(String expression, String one, String two){
    
            return Arrays.stream(expression.split(one, -1))
                         .map(s -> s.replaceAll(two, one))
                         .collect(Collectors.joining(two));
        }
        public static void main(String[] args) {
            String expression = "A * (B + C) / D";
            String result = new InfixToPrefixExpression().swapStrings(expression,
                             "\\(","\\)");
            System.out.println(result);
        }
}

如何删除结果字符串中出现的多余反斜杠?我也尝试了以下方法,但 String.join() 方法在结果中添加了额外的斜杠。

//        String[] split = expression.split(one, -1);
//        for (int i = 0; i < split.length; i++) {
//            split[i] = split[i].replaceAll(two, one);
//        }
//        String result = String.join(two, split);

【问题讨论】:

    标签: java escaping


    【解决方案1】:

    一种简单的交换方法可能是将"(" 换成"_" 这样的特殊字符,然后将")" 换成"(",最后将"_" 换成")",如下所示:

        final String expression = "A * (B + C) / D";
        final String result = expression
                .replace("(", "_")
                .replace(")", "(")
                .replace("_", ")");
    

    如果你不想使用特殊字符,你可以用一个括号来分割表达式,如下所示:

        final String expression = "A * (B + C) / D";
    
        final String[] substrings = expression.split("\\(");
        final List<String> replacedSubstrings = new ArrayList<>();
        for (String substring : substrings) {
            replacedSubstrings.add(substring.replace(")","("));
        }
    
        final String result = String.join(")", replacedSubstrings);
    

    【讨论】:

    • 谢谢。我想知道为什么不需要在 substring.replace()String.join() 函数中转义大括号?我显然在这里遗漏了一个微妙的点。
    • String#split 的参数是一个正则表达式(en.wikipedia.org/wiki/Regular_expression),而在正则表达式中,括号有特殊的含义,所以必须转义。您还必须转义转义字符,因此 Java 不会将 \( 解释为特殊字符。另一方面,String#replace 将 CharSequence 作为参数,因此不需要任何转义。
    【解决方案2】:

    您可能需要提供在正则表达式和Collectors.joining 中使用的特殊值:

    private static String swapStrings(String expression, String one, String two){
    
        String reOne = "\\" + one;
        String reTwo = "\\" + two;
    
        return Arrays.stream(expression.split(reOne, -1))
                .map(s -> s.replaceAll(reTwo, one))
                .collect(Collectors.joining(two));
    }
    

    那么这个方法可以在不转义括号的情况下调用:

    String expression = "A * (B + C) / D";
    String result = swapStrings(expression, "(",")");
    
    System.out.println(result);
    

    输出:

    A * )B + C( / D
    

    【讨论】:

    • 谢谢。为什么使用转义大括号调用函数时行为会发生变化 - swapStrings(expression, "\(","\)")?当我使用修改后的代码时,Intellij 还抱怨“非法/不支持的转义序列”,但是它编译成功。
    • 嗨,"\(" 中关于“非法/不支持的转义序列”的错误很明显,escape sequences 使用的字符集有限:`` \n \t \r \b \ f \' \" \\ ``。发生 IntelliJ 警告是因为此 IDE 检查字符串是否将在正则表达式中使用(split 的参数),如果 \\ 未正确转义,可能不正确。虽然 IDE“不能”看到我们要转义 另一个字符。也就是说,如果你替换使用代码String reOne = "\\(";,此警告消失了。
    • 我的错,有两个问题: 1. 为什么当原始代码做基本相同的事情时行为会不同。 (认为​​我之前评论中复制的代码搞砸了)? 2. Intellij 抱怨声明String reOne = "\\" + one; 虽然编译正常。
    • 1.在正则表达式中(如split),括号必须被转义,额外的\\被正则表达式引擎消耗;在纯字符串(String.join / Collectors.joining)中,不需要转义括号,并且不会消耗 \\ - 这就是为什么您在原始代码中有额外的 \\ 。 2. IntelliJ 有自己的功能来检查 regexp 可能存在的问题,而 Java 编译器不关心这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-15
    • 2014-04-10
    • 1970-01-01
    • 2012-12-14
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    相关资源
    最近更新 更多