如何用单个正则表达式模式替换过多的SQL通配符?

时间:2019-06-05 01:50:54

标签: java regex

我正在创建一个从输入字符串中剥离非法通配符模式的函数。理想的解决方案应尽可能使用单个正则表达式。

非法的通配符模式为:%%%_%。这些实例的每个实例都应替换为%

这是麻烦所在...我正在通过对各种输入运行该函数以使其制作并破坏它的功能来进行一些模糊测试。

大多数情况下有效;但是,对于复杂的输入,却不是。

此问题的其余部分已更新:

以下输入应返回空字符串(而不是详尽列表):

以下输入应返回%(而不是详尽列表)。

  • %_%
  • %%
  • %% _ %%
  • %_ %%%
  • %% _%_%
  • %% _ %%% _ %%% _%

在某些情况下,输入中还会包含其他字符...

  • Foo123%_%
    • 应返回“ Foo123%”
  • B4r $%_%
    • 应返回“ B4r $%”
  • B4rs %% _%
    • 应返回“ B4rs%”
  • %% Lorem _ %%
    • 应返回“%Lorem _%”

我尝试使用几种不同的模式,但测试失败。

String input = "%_%%%%_%%%_%";

// old method:
public static String ancientMethod1(String input){
    if (input == null)
        return "";
    return input.replaceAll("%_%", "").replaceAll("%%", "");  // Output: ""
}

// Attempt 1:
// Doesn't quite work right.
// "A%%" is returned as "A%%" instead of "A%"
public static String newMethod1(String input) {
    String result = input;
    while (result.contains("%%") || result.contains("%_%"))
        result = result.replaceAll("%%","%").replaceAll("%_%","%");
    if (result.equals("%"))
        return "";
    return input;
}

// Attempt 2:
// Succeeds, but I would like to simplify this:
public static String newMethod2(String input) {
    if (input == null)
        return "";

    String illegalPattern1 = "%%";
    String illegalPattern2 = "%_%";
    String result = input;

    while (result.contains(illegalPattern1) || result.contains(illegalPattern2)) {
        result = result.replace(illegalPattern1, "%");
        result = result.replace(illegalPattern2, "%");
    }

    if (result.equals("%") || result.equals("_"))
        return "";

    return result;
}

这是我如何使用此方法的更完整的定义示例:https://gist.github.com/sometowngeek/697c839a1bf1c9ee58be283b1396cf2e

4 个答案:

答案 0 :(得分:1)

此正则表达式字符串匹配您的所有示例:

"%(?:_?%)+"

它匹配由'%'字符组成的字符串,然后由一个或多个由零个或一个'_'字符和一个'%'字符组成的序列(接近直译)组成,这是我所做的另一种表示方式在注释中:“由'%'和'_'字符组成的序列,以'%'开头和结尾,并且不包含两个连续的'_'字符”。

答案 1 :(得分:1)

您的newMethod1实际上可以工作,除了您有错字-您将返回输入参数,而不是处理结果!

更改:

return input; // oops!

收件人:

return result;

另外,因为您没有使用正则表达式,所以应该使用replace()而不是replaceAll(),即:

result = result.replace("%%","%").replace("%_%","%"); // still replaces all occurrences

replace()仍将替换所有出现的内容。


顺便说一句,尽管不那么严格,但这适用于您所有(当前)发布的示例:

public static String myMethod(String input) {
    return input.replaceAll("%[%_]*", "%");
}

答案 2 :(得分:0)

我不太确定,如果列出的输入可能还有其他实例,如果没有,那么带有开始和结束锚点的表达式可能会在这里非常适用,无论是一个接一个还是类似以下内容:

^%{1,3}(_%{1,3})?(_%{1,3})?(_%)?$

Demo

测试

import java.util.regex.Matcher;
import java.util.regex.Pattern;

final String regex = "^%{1,3}(_%{1,3})?(_%{1,3})?(_%)?$";
final String string = "%_%\n"
     + "%%\n"
     + "%%_%%\n"
     + "%%%_%%%\n"
     + "%_%%%\n"
     + "%%%_%\n"
     + "%%_%_%\n"
     + "%%_%%%_%%%_%";

final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);

while (matcher.find()) {
    System.out.println("Full match: " + matcher.group(0));
    for (int i = 1; i <= matcher.groupCount(); i++) {
        System.out.println("Group " + i + ": " + matcher.group(i));
    }
}

RegEx电路

jex.im可视化正则表达式:

enter image description here

答案 3 :(得分:0)

看起来所有模式都以%开头,然后有0+ %_个字符,并以%结尾。

仅使用

input = input.replaceAll("%[%_]*%", "%");

请参见regex demoregex graph

enter image description here

详细信息

  • %-一个%字符
  • [%_]*-0个或更多%_个字符
  • %-一个%字符。