2016-11-07 6 views
0

У меня есть два регулярных выражения. Я хочу удалить все совпадения второго, если они помещены внутри совпадений первого. В принципе, ничто не может сравниться с тем, что уже было согласовано. Пример:Удалить совпадение регулярных выражений, помещенных внутри других регулярных выражений

Первое регулярное выражение (жирный) - c\w+ находит слова, начинающиеся с c

Второе регулярное выражение (подчеркнуты) - me находит me

Результат: верблюд уход преступления прохладный дом среда расплава

me в c-словах также сопоставляются. Хочу, чтобы я хотел: верблюд преступление уход прохладно medium melt home

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

String text = "camel crime care cool medium melt home"; 

static final Pattern PATTERN_FIRST = Pattern.compile("c\w+"); 
static final Pattern PATTERN_SECOND = Pattern.compile("me"); 

// Save all matches 
List<int[]> firstRegexMatches = new ArrayList<>(); 
for (Matcher m = PATTERN_FIRST.matcher(text); m.find();) { 
    firstRegexMatches.add(new int[]{m.start(), m.end()}); 
} 

List<int[]> secondRegexMatches = new ArrayList<>(); 
for (Matcher m = PATTERN_SECOND.matcher(text); m.find();) { 
    secondRegexMatches.add(new int[]{m.start(), m.end()}); 
} 

// Remove matches of second inside matches of first 
for (int[] pos : firstRegexMatches) { 
     Iterables.removeIf(secondRegexMatches, p -> p[0] > pos[0] && p[1] < pos[1]); 
} 

В этом коде я хранить все матчи обоих в списке, попробуйте удалить из второго списка матчей помещается внутри первого списка совпадений.

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

+0

Я не понимаю, что вы пытаетесь сделать. Вы пытаетесь удалить их из строки, так что результатом будет '' cal cri care cool medium melt home ''? Если это так, ваш вопрос неясно. Кроме того, я не вижу никакого кода, который фактически удаляет что-либо из строки. Кроме того, что такое 'Iterables'? Это не в стандартной библиотеке Java, так что это? Apache? Гуавы? Я не могу сказать, что происходит без этой информации, но похоже, что ваш 'removeIf' удаляет одну из пар из созданного вами' List'. Это ничего не удаляет из строки. – ajb

+0

Кроме того, ваш первый шаблон находит любое «c», находится ли оно в начале слова или нет. – ajb

+0

@ajb Все совпадения были сохранены в списке. Я пытаюсь удалить их из второго списка регулярных выражений. Iterables от Guava, я не мог использовать функцию java 8 –

ответ

2

Прежде всего, вы можете достичь чего-то подобного слияния оба выражения в одно целое.

(^c\w+)|\s(c\w+)|(\w*me\w*) 

Если вы подходите к этому регулярному выражению каждый матч будет либо слово, начиная с «с», а затем несколько слов-символов или слово, содержащее «меня». Для каждого сопрягать вас тогда либо получить группу: (1) или (2) указывает на слово, начинающееся с «с» или (3), указывающий слово, содержащее «меня»

Однако заметим, что это работает только в случае, если вы знаете разделитель слов, в этом случае символ \ s.

Пример кода:

String text = "camel crime care cool medium melt home"; 

    final Pattern PATTERN = Pattern.compile("(^c\\w+)|\\s(c\\w+)|(\\w*me\\w*)"); 

    // Save all matches 
    List<String> wordsStartingWithC = new ArrayList<>(); 
    List<String> wordsIncludingMe = new ArrayList<>(); 

    for (Matcher m = PATTERN.matcher(text); m.find();) { 
     if(m.group(1) != null) { 
      wordsStartingWithC.add(m.group(1)); 
     } else if(m.group(2) != null) { 
      wordsStartingWithC.add(m.group(2)); 
     } else if(m.group(3) != null) { 
      wordsIncludingMe.add(m.group(3)); 
     } 
    } 

    System.out.println(wordsStartingWithC); 
    System.out.println(wordsIncludingMe); 

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

String[] words = "camel crime care cool medium melt home".split(" "); 

Вы тогда просто перебираете все эти.

for(String word: words) {     
    if(word.startsWith("c")) { 
     // put in your list for words starting with "c" 
    } else if (word.contains("me")) { 
     // put in your list for words containing "me" 
    } 
} 

Это приведет к двум спискам без повторяющихся записей, как второе, если оператор будет выполняться только в случае, если первый терпит неудачу.

+0

Я использовал первый подход для своего кода, думая, что matcher.group() даст, какая группа в регулярном выражении сделала совпадение. Если, например, совпадение было словом, начинающимся с 'c', оно возвращалось бы 1, потому что группа 1 сделала совпадение. Однако, это не так. Вы знаете какой-либо способ получить эту ценность? –

+0

@Croutonix Я просто добавил пример того, как он может работать, принимая первый подход. Поскольку в настоящее время у меня нет IDE, я только что скомпилировал и запустил его на tutorialspoint, на котором он, похоже, работал. – Endzeit

1

Нельзя ли комбинировать два Regexes? Например, после того, как mec можно найти, используя один Regex с этим кодом:

((?<=c)|(?<=c\w)|(?<=c\w{2})|(?<=c\w{3})|(?<=c\w{4})|(?<=c\w{5}))me 

Проверьте это здесь: https://regex101.com/r/bfNkvF/2

+0

Нет, это не работает, потому что мне нужно делать две отдельные вещи с помощью регулярных выражений, и с этим я не могу их разграничить (может я?) –

+0

Нет, вы не можете, если не используете группы или другое регулярное выражение. – Ibrahim

Смежные вопросы