【问题标题】:How to distinguish two regular expressions, with one being the substring of the other?如何区分两个正则表达式,一个是另一个的子字符串?
【发布时间】:2017-06-08 02:51:42
【问题描述】:

我有两种模式,如下:

  • 第一类:${<varName>}
  • 类型二:$${<varName>}

这些模式可以单独找到,也可以在一个字符串中包含多个匹配项。我需要找到这些模式的出现,所以我写了一个查询来通过匹配正则表达式进行搜索。然而,问题在于,对于任何类型 II 模式,它们本身都包含与类型 I 模式的匹配项。例如,$${newVar} 将被检测为两次$${newVar}${newVar}。我只希望前者被退回。我使用的正则表达式是:

  • 第一类:\$\{[a-zA-Z0-9]+\}
  • 二类:\$\$\{[a-zA-Z0-9]+\}

可以查看检测到的字符串here的示例(下)

请注意,第二次检测是正确的,而第一次检测是不需要的。

还有没有修改这些正则表达式来满足我的需要?或者有其他选择吗?请随时提出建议。欢迎大家回答!!谢谢大家。

【问题讨论】:

  • 你的Type II不应该是\$\$\{[a-zA-Z0-9]+\}吗?对于 I 类,你不能有[^\$]\$\{[a-zA-Z0-9]+\}吗?
  • 为错字道歉,它是\$\$。对于您建议的正则表达式,我已经尝试过了,它会匹配模式前面的任何字符,例如fasdfasd'f${var}'' 表示匹配)
  • 你说得对,我忘了它会包含在捕获中。它可能需要一个前瞻性,但我对那些提供解决方案的人不够好。

标签: java regex


【解决方案1】:

您似乎需要找到两种类型 I 和类型 II 模式的出现,因此您应该在一次扫描中完成。

可以这样做:

String input = "adklsfjb$${xxx}dklsjfnsdklj${yyy}";

Pattern p = Pattern.compile("(\\$)?\\$\\{([^}]+)}");
for (Matcher m = p.matcher(input); m.find(); ) {
    if (m.start(1) == -1) {
        System.out.println("Found Type I match for variable '" + m.group(2) + "'" +
                           " at index " + m.start() + "-" + m.end());
    } else {
        System.out.println("Found Type II match for variable '" + m.group(2) + "'" +
                           " at index " + m.start() + "-" + m.end());
    }
}

输出

Found Type II match for variable 'xxx' at index 8-15
Found Type I match for variable 'yyy' at index 27-33

更新

如果你想用值替换模式,你可以使用appendReplacement()appendTail()

例子:

String input = "adklsfjb$${xxx}dklsjfnsdklj${yyy}adljfhjh";

Map<String, String> type1 = new HashMap<>();
type1.put("xxx", "[type I with x's]");
type1.put("yyy", "[type I with y's]");

Map<String, String> type2 = new HashMap<>();
type2.put("xxx", "{TYPE 2 WITH x's}");
type2.put("yyy", "{TYPE 2 WITH y's}");

StringBuffer buf = new StringBuffer();
Matcher m = Pattern.compile("(\\$)?\\$\\{([^}]+)}").matcher(input);
while (m.find()) {
    String var = m.group(2);
    String repl = (m.start(1) == -1 ? type1.get(var) : type2.get(var));
    if (repl != null)
        m.appendReplacement(buf, Matcher.quoteReplacement(repl));
}
String output = m.appendTail(buf).toString();

System.out.println(output);

输出

adklsfjb{TYPE 2 WITH x's}dklsjfnsdklj[type I with y's]adljfhjh

【讨论】:

  • 在 Java 的正则表达式引擎 +1 中非常巧妙地使用了一种模式。感觉有必要对此投赞成票。
  • 非常感谢您的回答!!你绝对救了我!!
  • @mrawesome 如果这是您正在寻找的答案,请点击复选标记接受它,以便其他人可以看到您的问题得到了满意的回答。
  • 已标记。感谢您的指导,我是 SO 新手 :)
【解决方案2】:

对于${varname} 类型的变量,您可以使用这种模式:

(^|[^$])\$\{.*?\}

对于$${varname} 类型的变量,您可以使用您已经想到的:

\$\$\{.*?\\}

示例代码:

String input = "${beef} is a great thing to $${eat}.  It has many ${health} benefits ";
       input + "and is low in fat ${too}";

// single dollar sign variables
System.out.println("single dollar sign variables:");
String pattern = "(?:^|[^$])(\\$\\{.*?\\})";
Pattern r = Pattern.compile(pattern);

Matcher m = r.matcher(input);
while (m.find()) {
    System.out.println("Found value: " + m.group(1));
}

// two dollar sign variables
System.out.println("two dollar sign variables:");
pattern = "(\\$\\$\\{.*?\\})";
r = Pattern.compile(pattern);

m = r.matcher(input);
while (m.find()) {
    System.out.println("Found value: " + m.group(1));
}

输出:

single dollar sign variables:
Found value: ${beef}
Found value: ${health}
Found value: ${too}
two dollar sign variables:
Found value: $${eat}

演示在这里:

Rextester

【讨论】:

  • 我没有在 Java 代码中尝试过你的答案,但是当我输入 regexr.com 时,匹配的字符串还包含前缀字符。在您的输入字符串中,前缀字符都是空格,所以这应该不是问题,但是我也在处理 URL,所以我可能需要再过滤一次结果。无论如何感谢您的建议:)
  • 您输入了错误的正则表达式。使用我的 Java 代码中的正则表达式:(?:^|[^$])(\$\{.*?\\}) ... 这应该可以正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-28
  • 2013-09-14
相关资源
最近更新 更多