正则表达式替换嵌套的标记

时间:2015-08-06 13:39:10

标签: java regex

我需要采用正则表达式模式并以编程方式转义花括号。输入正则表达式将匹配以下模式(标签之前,之后和之间的文本):

&{token1}
&{token1}&{token2}&{tokenN...}
&{token1&{token2&{tokenN...}}}

到目前为止,我对除嵌套标签之外的所有内容都很好。这就是我所拥有的。

regex = regex.replaceAll("(&)(\\{)([^{}]+)(\\})", "$1\\\\$2$3\\\\$4");

我也试过使用迭代和递归,但我遇到的问题是,一旦最内层的令牌被转义,它就会与匹配混乱。

我尝试过负面的看守,但这并不符合我的预期。它只会匹配/替换最里面的令牌。

regex = regex.replaceAll("(&)(\\{)([^(?<!\\\\{)|(?<!\\\\})]+)(\\})", "$1\\\\$2$3\\\\$4");

有什么建议吗?提前谢谢。

编辑:示例输入/输出

&{token1}   //input
&\{token1\} //output

&{token1}&{token2}&{tokenN...}        //input
&\{token1\}&\{token2\}&\{tokenN...\}  //output

&{token1&{token2&{tokenN...}}}        //input
&{token1&{token2&\{tokenN...\}}}      //output
&\{token1&\{token2&\{tokenN...\}\}\}  //expected output

//To throw a wrench into it, normal quantifiers should not be escaped
text{1,2}&{token1&{token2&{tokenN...}}}        //input
text{1,2}&{token1&{token2&\{tokenN...\}}}      //output
text{1,2}&\{token1&\{token2&\{tokenN...\}\}\}  //expected output

编辑2:在此过程之外发生的事例的示例:标签将被解析为文本,然后最终,它应该是有效的正则表达式。

a{2}&{token1&{token2&{tokenN...}}}        //input
a{2}&\{token1&\{token2&\{tokenN...\}\}\}  //expected output of this regex
a{2}foobarbaz                             //expected output after tokens are resolved (&{token1} = foo, &{token2} = bar, &{tokenN...} = baz) 

2 个答案:

答案 0 :(得分:1)

尝试:

regex = regex.replaceAll("(?<=&)(?=\\{)|(?<!\\{\\d{0,6},?(\\d{0,6})?)(?=\\})","\\\\");

其中(0,6)确定可以有多少位数,我认为6就足够了 Java示例:

public class Main {
    public static void main(String[] args){
        int i = 0;
        String regex = "&{token1}&{token2}&{tokenN}\n" +
                "&{token1&{token2&{tokenN}}}\n" +
                "text{1,2}&{token1{1}&{token2{1,}&{tokenN{0,2}}}}\n";
        regex = regex.replaceAll("(?<=&)(?=\\{)|(?<!\\{\\d{0,6},?(\\d{0,6})?)(?=\\})","\\\\");
        System.out.println(regex);
    }
}

带输出:

&\{token1\}&\{token2\}&\{tokenN\}
&\{token1&\{token2&\{tokenN\}\}\}
text{1,2}&\{token1{1}&\{token2{1,}&\{tokenN{0,2}\}\}\}

答案 1 :(得分:1)

我会避免正则表达式并创建简单的状态机,它将存储有关{转义的决策序列。根据这些信息,每当我们找到}时,我们就可以做出适当的决定来逃避或取消它并删除最后的信息,因为我们不再需要它了。

所以你的代码看起来像

public static String myEscape(String text){
    StringBuilder sb = new StringBuilder();

    char prev = '\0';
    Stack<Boolean> stack = new Stack<>();

    for (char ch : text.toCharArray()){
        if (ch == '{'){
            if (prev == '&'){
                sb.append('\\');
            }
            stack.push(prev == '&');
        }else if (ch == '}'){
            if (stack.pop()){
                sb.append('\\');
            }
        }
        sb.append(ch);
        prev = ch;
    }
    return sb.toString();
}

示例:

text{1,2}&{token1&{token2{foo}...}}
  • 我们首先找到{并看到它之前没有&我们放在堆栈false
  • 当我们找到}并基于堆栈的最高值(false)时,决定不应对其进行转义
  • 我们看到另一个{,因为它前面有&,我们放在堆栈true
  • 之上
  • 我们找到另一个{,因为它前面还有&,我们将其放在堆栈顶部另一个true
  • 我们发现另一个{这次没有&,所以我们放在堆栈顶部false

因此,当我们看到堆栈存储信息有关我们是否应该转发}时,false -> true -> true当前}我们可以看到下一个}意味着我们应该期待\} } \} @Named(value = "filterBean") @ViewScoped public class FilterBean { private List<Clientactions> filterDept; public FilterBean() { } public List<Clientactions> getFilterDept() { return filterDept; } public List<Clientactions> getFilterDept() { return filterDept; } public void setFilterDept(List<Clientactions> filterDept) { this.filterDept = filterDept; } // rest of bean code