匹配字符串中某些未被某些字符分隔的关键字

时间:2012-05-02 19:09:38

标签: java regex

在Java程序中,我想找出这些子串的给定String中出现的所有事件:$$或$ \ d(符号'$'后跟一个整数)。

当我添加一个附加约束时,我的问题就开始了,只有当匹配的字符串不是由特定字符序列限制的子字符串的一部分时才会发生匹配。

例如,我想忽略匹配项,如果它们是由“/ {”和“/}”包围的子字符串的一部分。

以下示例显示了$$或$ \ d的所有出现次数,但如果它位于“/ {”和“/}”之内,则不考虑忽略匹配的附加约束。

public static final String PARAMETERS_PREFIX = "$";
public static final String ALL_PARAMS_SUFFIX = "$";
public static final String BEGIN_JAVA_EXPRESSION = "/{";
public static final String END_JAVA_EXPRESSION = "/}";
...
String test = "$1 xxx $$ " //$1 and $$ are matches
  + BEGIN_JAVA_EXPRESSION + "xxx $2 xxx" + END_JAVA_EXPRESSION; //$2 SHOULD NOT be a match
Set<String> symbolsSet = new LinkedHashSet<String>();
Pattern pattern = Pattern.compile(Pattern.quote(PARAMETERS_PREFIX)+"(\\d+|"+Pattern.quote(ALL_PARAMS_SUFFIX)+")");
Matcher findingMatcher = pattern.matcher(test);
while(findingMatcher.find()) {
  String match = findingMatcher.group();
  symbolsSet.add(match);
}
return new ArrayList<String>(symbolsSet);

除了找到不属于某个子字符串的关键字之外,我希望之后只能按某些值替换这些关键字。 然后,在执行匹配之前只删除分隔字符之间的所有内容的选项可能无济于事,因为之后我需要能够获取原始字符串,匹配的标记被某些值替换,并且分隔区域内的标记应该留下没有修改。 如果我找到了正确的正则表达式,这应该很容易。

有人可以给我一个关于如何为这个问题编写正确的正则表达式的提示吗?

6 个答案:

答案 0 :(得分:2)

是否可以使用超过1个正则表达式?它可能不那么性感,但你可以很容易地用3个正则表达式做到这一点。 (这些不是真正的正则表达式) 1.获取你要找的字符串($$ | $ {num}) 2.'/ {' 3.对于'/}'

匹配2和3中的无效区域应该相当容易。然后可以使用这些跨度来消除1中的结果

答案 1 :(得分:1)

我建议为此使用多个正则表达式。试图一次完成所有这一切 - 虽然诱人 - 似乎相当混乱。

  1. 从字符串中删除“Java表达式”:/{.*?/}
  2. 在生成的字符串上运行匹配器:\$(?:\d+)?
  3. 注意:我对第一个表达式很懒,所以它假定/{的任何出现最终都会被/}跟踪并且没有嵌套。

答案 2 :(得分:1)

使用此正则表达式可以实现您需要的第一部分:

(?<!/{)\($[$|\d])(?!}/)

因此,在运行之后,您将获得所有匹配的组 - 从现在开始,您可以通过评估组中的匹配并找到合适的替代品来让Java完成艰苦的工作。

你应该能够以某种方式使用反向引用替换位,但我想你可以搞清楚。

更新:

(?<!/{) - 这是一个负面的背后 - 它说:从当前位置断言前面的字符不是/{。如果此计算结果为true,则将丢弃/ {匹配并开始实际匹配。 Lookahead / lookbehind是零宽度断言,不参与匹配。

(?!}/) - 同样但在另一个方向 - 从当前位置声明以下字符不是} /。这些也不参加比赛。如果满足这些条件,那么你的匹配仍然只是断言中的文本,即$$或$ \ d。

顺便说一句:你可能需要逃避一些角色 - 我记得的是{和$外面的角色等级

(?<!/\{)\(\$[$|\d])(?!}/)

另见: How to escape text for regular expression in Java

答案 3 :(得分:0)

我不是RegExp的专家,所以我会尝试使用计数器来计算{}的数量。 {表示+1 }表示-1 如果计数器为0,那么使用正则表达式是安全的。如果计数器不是0,那么尝试regexp是没用的。我确信这只是RegExp的解决方案,但同样,我不是它的主人。

答案 4 :(得分:0)

我不确定你能用一个正则表达式做到这一点。如果没有人能提供这种终极正则表达式,我做了一点解决方法:

public static final String PARAMETERS_PREFIX = "$";
public static final String ALL_PARAMS_SUFFIX = "$";
public static final String BEGIN_JAVA_EXPRESSION = "/{";
public static final String END_JAVA_EXPRESSION = "/}";

    String test = "$1 xxx $$ " //$1 and $$ are matches
    + BEGIN_JAVA_EXPRESSION + "xxx $2 xxx" + END_JAVA_EXPRESSION; //$2 SHOULD NOT be a match
    Set<String> symbolsSet = new LinkedHashSet<String>();
    Pattern pattern = Pattern.compile(Pattern.quote(PARAMETERS_PREFIX)+"(\\d+|"+Pattern.quote(ALL_PARAMS_SUFFIX)+")");
    Matcher findingMatcher = pattern.matcher(test);
    while(findingMatcher.find()) {
        String match = findingMatcher.group(0);
        int idx= findingMatcher.start();
        int bexIdx = test.lastIndexOf(BEGIN_JAVA_EXPRESSION,idx);
        if(bexIdx!=-1){
            int endIdx = test.indexOf(END_JAVA_EXPRESSION,bexIdx);
            if(endIdx<idx){
                symbolsSet.add(match);
            }
        }
        else{
            symbolsSet.add(match);
        }
    }

答案 5 :(得分:0)

您可以将图案与Lookaround

一起使用

(?<!\\{[^\\}]{0,100})\\$(\\d|\\$)(?![^\\{]*\\})

  • (?<!\\{[^\\}]{0,100})用于限制前置值的组。

    这使用负面的lookbehind:{?<!X},其中X是一个不能在主表达式之前的正则表达式。在Java中,如果没有明显的最大长度,则不能使用负lokbehind,那么就不能使用\\{.*。您可以使用Integer.MAX_VALUE,ou testString.length()。另一件事:您必须检查在开始符号之前是否找到了结束符号。因此,表达式为[^\\}]而非.

  • \\$(\\d|\\$)主要群体寻求

    通常在这里。

  • (?![^\\{]*\\})用于限制后验值的组

    这使用负向前瞻:{?!X},其中X是一个正则表达式,无法成功使用主表达式。在这里,您可以使用无固定长度。同样,您必须检查是否找到了子串的起始符号。然后,您使用[^\\{]*代替.*

但是,添加更多约束会增加正则表达式的复杂性。


测试模式的字符串:"$1 xx3x $$ /{xxx $2 xxx/} $4"