1

在 Java 程序中,我想找出这些子字符串在给定字符串中的所有出现:$$ 或 $\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);

除了查找不属于某些子字符串的关键字之外,我还希望之后能够仅用某些值替换那些关键字。然后,在进行匹配之前仅删除分隔字符之间的所有内容的选项可能无济于事,因为之后我需要能够获取原始字符串,并将匹配的标记替换为某些值,并且分隔区域内的标记应该保持不变。如果我找到了正确的正则表达式,这应该很容易。

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

4

5 回答 5

2

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

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

于 2012-05-02T19:17:15.367 回答
1

我建议为此使用多个正则表达式。试图一次完成所有事情——虽然很诱人——似乎很麻烦。

  1. 从字符串中删除“Java 表达式”:/{.*?/}
  2. 在结果字符串上运行匹配器:\$(?:\d+)?

注意:我对第一个表达式很懒惰,所以它假定任何出现的/{最终都会跟随/}并且没有嵌套。

于 2012-05-02T19:26:35.273 回答
1

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

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

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

您应该能够以某种方式使用反向引用来进行替换,但我想您可以弄清楚。

更新:

(?<!/{)- 这是一个消极的向后看 - 它说:从当前位置断言前面的字符不是/{. 如果计算结果为真,则 /{ 的匹配被丢弃,真正的匹配开始。Lookahead/lookbehind 是不参与匹配的零宽度断言。

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

顺便说一句:您可能需要转义一些字符 - 我记得的是 { 和 $ 外部字符类

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

另请参阅: 如何在 Java 中为正则表达式转义文本

于 2012-05-02T20:20:44.160 回答
0

您可以使用带有Lookaround的 Pattern :

(?<!\\{[^\\}]{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"

于 2012-05-02T20:32:44.337 回答
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);
        }
    }
于 2012-05-02T20:09:57.070 回答