2014-08-04 4 views
4

Я пытаюсь написать Java-регулярное выражение, которое найдет все строки между 2 :. Если строка между символами имеет пробелы, концы строк или вкладки, ее следует игнорировать. Пустые строки также игнорируются. _ в порядке! Группа может либо включать в себя приложение :, либо нет.Java Regex: соответствие строки между двумя двоеточиями

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

"test :candidate: test" => ":candidate:" 
"test :candidate: test:" => ":candidate:" 
"test :candidate:_test:" => ":candidate:", ":_test:" 
"test :candidate::test" => ":candidate:" 
"test ::candidate: test" => ":candidate:" 
"test :candidate_: :candidate: test" => ":candidate_:", ":candidate:" 
"test :candidate_:candidate: test" => ":candidate_:", ":candidate:" 

Я проверил много регулярных выражений и это те, почти работа:

":(\\w+):" 
":[^:]+:" 

Я до сих пор есть проблемы, когда 2 группы «доля» двоеточие:

"test :candidate_: :candidate: test" => ":candidate_:", ":candidate:" // OK 
"test :candidate_:candidate: test" => ":candidate_:" // ERROR! :(

Похоже, что первая группа «потребляет» второй двоеточие и коврик cher не может найти вторую строку, которую я ожидал.

Может кто-нибудь указать мне в правильном направлении, чтобы решить эту проблему? Можете ли вы также уточнить, почему помощник «потребляет» двоеточие?

Спасибо.

+0

Вы считаете обрабатывать строку по-разному?Вместо использования сокетов и т. Д. Большая часть подъема может быть выполнена с помощью String # split –

+0

Да, я думал о 'split()', но я хотел понять, как это сделать с помощью регулярного выражения. Я думаю, что я буду использовать этот метод, если не могу найти решение регулярного выражения. –

+0

Какой метод регулярного выражения вы используете? Вам нужно захватить каждую:: область с разделителями внутри группы соответствия, не так ли? –

ответ

5

Используйте Positive Lookahead для захвата, чтобы получить совпадающие совпадения.

(?=(:\\w+:)) 

Примечание: Вы можете получить доступ к результату матча по ссылаюсь для захвата группы #1 (Live Demo)

+0

Я думал больше о ': \\ w + (? = (:))', но это тоже поможет. +1, но вы, вероятно, должны быть более явными, что соответствующая часть будет в группе 1. – Pshemo

+0

@Pshemo решение работает хорошо! Благодаря! –

+0

Решение VincentDurmont Mine потребует объединения совпадений из группы 0 и группы 1 (если вы также хотите включить в столбец последний ':'). В этом решении вам просто нужно использовать группу 1. Но если вы не хотите включать ':' в соответствие, вы можете просто использовать '(? <=:) \\ w + (? = :)' и получить результат из группа 0. – Pshemo

4

Как насчет String.split()?

String invalidChars = " |\t|\r|\f|\n"; // regex for invalid characters 

String testStr = "test :candidate:_test:"; 
String[] parts = testStr.Split(":"); 
List<String> results = new ArrayList<String>(); 
for (String part : parts) 
{ 
    if (part.matches(invalidChars) || part.isEmpty()) continue; 
    results.add(part); 
} 

results должен содержать candidate и _test.

+0

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

+0

@PatrickCollins Я почти всегда согласен с этим. :) – Jashaszun

+0

Спасибо за ваш ответ. Я думал о 'split()', но мне было интересно, было ли более легкое решение с регулярным выражением. –

1

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

String[] terms = input.replaceAll("(?s)^.*?:|:[^:]*$", "").split("(?s):([^:]*\\s[^:]*:)?"); 

Это работает для всех краевых случаев по:

  • удаление входных данных с головы и хвоста (включая ведущие/задние двоеточия)
  • расщепление на двоеточие, необязательно сопровождаемое мусором и другим двоеточием
  • флаг «dotall» (?s) делает его работу на несколько строк

Вот некоторые тестовый код:

String[] inputs = { 
     "foo:target1:bar", 
     "foo:target1:target2:bar", 
     "foo:target1:target2:target3:bar", 
     "foo:target1:junk junk:target2:bar" , 
}; 
for (String input : inputs) { 
    String[] terms = input.replaceAll("(?s)^.*?:|:[^:]*$", "").split("(?s):([^:]*\\s[^:]*:)?"); 
    System.out.println(Arrays.toString(terms)); 
} 

Выход:

[target1] 
[target1, target2] 
[target1, target2, target3] 
[target1, target2] 
+0

Я не уверен, что это работает как OP, так как 'target2' игнорируется (или фактически является частью' .split (": (. * :)?"); 'Поэтому он потребляется, оставив нам только« target1 »и 'target3'. – Pshemo

+0

@Pshemo yes - вот что это делает. Ввод ввода - это то, что этот код * не обрабатывает. Он обрабатывает' 'foo: target1: junk: target2: bar" и '" foo: target1 : target2: bar "' – Bohemian

+0

Если я правильно понимаю OP, 'junkxxx' на самом деле является правильным значением, потому что внутри него нет пробелов, поэтому IMHO он должен быть включен в результат (но я могу ошибаться, OP должен был бы судить об этом решении). – Pshemo

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