Удалить все из строки, которой нет в списке разрешений, используя регулярное выражение

#java #regex

#java #регулярное выражение

Вопрос:

Следующее регулярное выражение удаляет каждое слово из строки:

 String regex = "\b(operation|for the|am i|regex|mountain)\b";
String sentence = "I am looking for the inverse operation by using regex";
String s = Pattern.compile(regex).matcher(sentence.toLowerCase()).replaceAll("");
System.out.println(s); // output: "i am looking  inverse  by using "
 

Я ищу обратную операцию с помощью регулярного выражения. Итак, следующий пример должен работать.
Слова «я» и «гора» просто указывают на то, что в списке может быть гораздо больше слов. А также в списке могут встречаться слова с пробелами.

 String regex = "<yet to find>"; // contains words operation,for the,am i,regex,mountain
String sentence = "I am looking for the inverse operation by using regex";
String s = Pattern.compile(regex).matcher(sentence.toLowerCase()).replaceAll("");
System.out.println(s); // output: "  for the  operation  regex"
 

С уважением, Харрис

Комментарии:

1. Спасибо @GurmanjotSingh за ваш ответ! Это работает как шарм, за исключением случаев, когда я проверяю строку «привет». Он возвращает «привет» вместо ожидаемого «».

2. Я не думаю, что одна замена регулярного выражения может сделать это за вас. ИМХО, лучший способ — использовать сопоставитель для положительного регулярного выражения и собрать все совпадения в качестве результата.

Ответ №1:

Попробуйте использовать регулярное выражение:

 (?:(?!for the|operation|am i|mountain|regex).)*(for the|operation|am i|mountain|regex|$)
 

Замените совпадения содержимым группы 1 1 или $1

Нажмите для демонстрации

Нажмите для получения кода

Объяснение:

  • (?:(?!for the|operation|am i|mountain|regex).)* — соответствует 0 вхождениям любого символа, за которым НЕ следует ни for the или или operation или am i или mountain или regex
  • (for the|operation|am i|mountain|regex|$) — соответствует или for the или operation или am i или mountain или regex или концу строки и записывает ее в группу 1

Ответ №2:

Чтобы расширить ответ Сингха в комментариях, я бы добавил, что жесткое кодирование регулярного выражения для набора слов не очень переносимо. Что, если слова изменятся? Это просто слова или шаблоны? Можете ли вы выделить часть кода, которая будет выполнять эту работу, и протестировать ее?

Предполагая, что это просто слова:

  1. Определите белый список
     String[] whitelist = {
       "operation",
       "for",
       "the",
       "am i",
       "regex",
       "mountain"
    };
     
  2. Напишите метод для фильтрации слов, чтобы разрешались только те, которые занесены в белый список.
      String sanitized(String raw, String[] whitelist) {
         StringBuilder termsInOr = new StringBuilder();
         termsInOr.append("|");
         for (String word : whitelist) {
             termsInOr.append(word);
         }
         String regex = ".*?\b("   termsInOr.substring(1)   ")\b";
         return Pattern.compile(regex, Pattern.MULTILINE)
             .matcher(raw)
             .replaceAll(subst);
     }
     

Таким образом, логика изолирована, у вас есть два входа — белый список и необработанная строка — и очищенный вывод. Его можно протестировать с помощью утверждений, основанных на вашем ожидаемом выходе (тестовых примерах), если у вас есть другой белый список или необработанная строка где-то еще в коде, вы можете вызвать метод с этой белой строкой / необработанной строкой для очистки.

Комментарии:

1. Спасибо за ваш ответ! Это регулярное выражение отлично работает для строк, содержащих хотя бы один элемент списка разрешений. Но если я проверю «привет» против этого регулярного выражения, оно вернет «привет» вместо «».