просмотр вперед и группа

В Java для такого текста, как foo <on> bar </on> thing <on> again</on> now, мне нужно регулярное выражение с группами, которые дают мне поиск «foo», «bar», пустую строку, затем «вещь», «снова», «сейчас».

Если я делаю (.*?)<on>(.*?)</on>(?!<on>), я получаю только две группы (foo bar, снова вещь, и у меня нет конца "сейчас").

если я делаю (.*?)<on>(.*?)</on>((?!<on>)), я получаю пустую строку foo bar, затем снова что-то и пустую строку (здесь я должен хотеть "сейчас").

Пожалуйста, что за волшебная формула?

Спасибо.


person Istao    schedule 21.05.2010    source источник
comment
Это очень похоже на XML. Это на самом деле XML? Если это так, используйте XML API вместо регулярного выражения.   -  person Jon Skeet    schedule 21.05.2010
comment
У тебя проблемы ? Вы хотите решить это с помощью регулярных выражений? Ну угадайте что?   -  person Riduidel    schedule 21.05.2010
comment
Откуда берется пустая строка?   -  person polygenelubricants    schedule 21.05.2010
comment
Да, это xml, но я пытаюсь использовать регулярное выражение :-) Я не понимаю комментарий Riduidel, извините.   -  person Istao    schedule 21.05.2010
comment
Regex по определению не может надежно работать с нестандартными языками, такими как XML. @Riduidel имеет в виду печально известную цитату Джейми Завински, которую вы, к сожалению, найдете в каждом другом вопросе о регулярных выражениях здесь, на SO, но в данном случае это уместно.   -  person Tim Pietzcker    schedule 21.05.2010
comment
@Tim: я бы не сказал, что Regex по определению.... Regular languages по определению... конечно, но однозначного регулярного выражения не существует. Вы правы, что люди злоупотребляют регулярными выражениями для подобных вещей.   -  person polygenelubricants    schedule 21.05.2010


Ответы (2)


Мои рекомендации

  • нет необходимости сопоставлять текст до <on> и после </on>
  • используйте нежадные флаги для сопоставления текста между <on> и следующим </on>
  • используйте цикл с Matcher.find() для последовательности всех вхождений, если это возможно. Не нужно делать все сразу с одним большим толстым регулярным выражением!
person Ingo    schedule 21.05.2010
comment
Отлично. Таким образом, ваша программа будет более читабельной и ремонтопригодной. - person Ingo; 21.05.2010

Если вы настаиваете на том, чтобы делать это с помощью регулярных выражений, вы можете попробовать использовать \s*<[^>]*>\s* в качестве разделителя:

    String text = "foo <on> bar </on> thing <on> again</on> now";
    String[] parts = text.split("\\s*<[^>]*>\\s*");
    System.out.println(java.util.Arrays.toString(parts));
    // "[foo, bar, thing, again, now]"

Я не уверен, что это именно то, что вам нужно, потому что это не совсем ясно.


Возможно, требовалось что-то вроде этого:

    String text = "1<on>2</on>3<X>4</X>5<X>6</X>7<on>8</on><X>9</X>10";
    String[] parts = text.split("\\s*</?on>\\s*|<[^>]*>[^>]*>");
    System.out.println(java.util.Arrays.toString(parts));
    // prints "[1, 2, 3, 5, 7, 8, , 10]"

Это не обрабатывает вложенные теги. Если они у вас есть, вам действительно нужно сбросить регулярное выражение и использовать настоящий парсер HTML.

Если вам не нужна пустая строка в середине массива, то просто (?:delimiter)+.

    String text = "1<on>2</on>3<X>4</X>5<X>6</X>7<on>8</on><X>9</X>10";
    String[] parts = text.split("(?:\\s*</?on>\\s*|<[^>]*>[^>]*>)+");
    System.out.println(java.util.Arrays.toString(parts));
    // prints "[1, 2, 3, 5, 7, 8, 10]"
person polygenelubricants    schedule 21.05.2010
comment
Нет, извините, я хочу ловить «на» и только «на», а не «в», например. - person Istao; 21.05.2010
comment
@Istao: Все еще не ясно. Зачем тогда нужны foo и thing? Отредактируйте вопрос с НАМНОГО БОЛЬШЕ примеров. - person polygenelubricants; 21.05.2010