Как заменить избыточный подстановочный знак SQL одним шаблоном регулярных выражений? - PullRequest
1 голос
/ 05 июня 2019

Я создаю функцию, которая удаляет недопустимые шаблоны из входной строки. Идеальное решение должно использовать одно выражение регулярного выражения, если это вообще возможно.

Недопустимые шаблоны: %% и %_%. Каждый их экземпляр должен быть заменен на %.

Вот в чем дело ... Я пытаюсь выполнить нечеткое тестирование, запустив функцию для разных входов, чтобы попытаться сделать это и сломать ее.

Работает по большей части; однако со сложными входами это не так.

Остальная часть этого вопроса была обновлена:

Следующие входные данные должны возвращать пустую строку (не исчерпывающий список):

Следующие входные данные должны возвращать % (не исчерпывающий список).

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

В некоторых случаях вводятся другие символы ... например:

  • 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 ]

1 голос
/ 18 июня 2019

Ваш 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("%[%_]*", "%");
}
1 голос
/ 05 июня 2019

Эта строка регулярного выражения соответствует всем вашим примерам:

"%(?:_?%)+"

Соответствует строкам, состоящим из символа «%», за которым следуют одна или несколько последовательностей, состоящих из нуля или одного символа «_» и одного символа «%» (близко к буквальному переводу), что является еще одним способом сказать, что я сделал в комментариях: «последовательность символов«% »и« _ », начинающаяся и заканчивающаяся«% »и не содержащая двух последовательных символов« _ »».

0 голосов
/ 05 июня 2019

Похоже, что все шаблоны начинаются с %, затем имеют 0+ % или _ символов и заканчиваются %.

Используйте просто

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

См. Демонстрационную версию regex и график regex :

enter image description here

Детали

  • % - % char
  • [%_]* - 0 или более % или _ символов
  • % - % char.
0 голосов
/ 05 июня 2019

Я не совсем уверен, если перечисленные входные данные могут иметь другие экземпляры, в противном случае, может быть, выражение с начальным и конечным якорем будет здесь очень подходящим, либо по одному, либо с чем-то похожим на:

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

Демо

Тест

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 Circuit

jex.im визуализирует регулярные выражения:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...