Нужно регулярное выражение, чтобы найти подстроку между двумя токенами

Я подозреваю, что на этот вопрос уже где-то отвечали, но я не могу его найти, поэтому...

Мне нужно извлечь строку из двух токенов в большую строку, в которой второй токен, вероятно, снова появится, что означает... (псевдокод...)

myString = "A=abc;B=def_3%^123+-;C=123;"  ;

myB = getInnerString(myString, "B=", ";" )  ;

method getInnerString(inStr, startToken, endToken){
   return inStr.replace( EXPRESSION, "$1");
}

поэтому, когда я запускаю это, используя выражение ".+B=(.+);.+", я получаю "def_3%^123+-;C=123;" предположительно, потому что он просто ищет ПОСЛЕДНИЙ экземпляр ';' в строке, а не останавливаться на первом, к которому он приходит.

Я пытался использовать (?=) для поиска этого первого ';' но это дает мне тот же результат.

Кажется, я не могу найти ссылку на regExp, которая объясняет, как можно указать токен «NEXT», а не тот, который находится в конце.

любая помощь очень ценится.


Аналогичный вопрос по SO:


person Yevgeny Simkin    schedule 28.01.2009    source источник
comment
dmckee, ваше редактирование кажется бессмысленным. Да, другие люди видели подобные вопросы, но это не обязательно означает, что они помогают.   -  person Evan Fosmark    schedule 29.01.2009
comment
@Evan: Если SO должен быть хранилищем хороших ответов, то несколько экземпляров отдельных вопросов будут разрушительными, если они не связаны между собой. Итак, я связываю. В основном назад, но иногда и вперед. Я отредактирую бедную Грейс. Никаких оправданий этому. --Ваше здоровье   -  person dmckee --- ex-moderator kitten    schedule 29.01.2009
comment
@dmckee - разве это не то, что должен делать механизм поиска? Вы только что вырезали/вставили результаты поиска регулярного выражения внутри или что-то в этом роде? Пожалуйста, не делайте этого - ссылки имеют длину самого вопроса и сильно отвлекают.   -  person    schedule 29.01.2009
comment
@Arkadiy: Я бы хотел, чтобы меня отговорили от этого, но ни поиск, ни соответствующая боковая панель не работают должным образом. Действительно, постоянное накопление повторов я рассматриваю как свидетельство того, насколько плохо работает поиск.   -  person dmckee --- ex-moderator kitten    schedule 29.01.2009
comment
@Arkadiy: Я получаю свои списки из вариантов, на которые я уже ответил, или из избранного, или могу вспомнить достаточно названия, чтобы найти его с помощью поиска (и из панели избранного из них).   -  person dmckee --- ex-moderator kitten    schedule 29.01.2009
comment
Аркадий, ответ Эвана был значительно лаконичнее остальных (что мне не удалось найти самостоятельно). Однако, если бы кто-то дал мне эти ссылки, я бы также сделал из них то, что мне было нужно, так что это было бы в равной степени полезно. Хотя не уверен, в чем проблема.   -  person Yevgeny Simkin    schedule 30.01.2009


Ответы (3)


Вы используете жадный шаблон, не указывая в нем ?. Попробуй это:

".+B=(.+?);.+" 
person Evan Fosmark    schedule 28.01.2009
comment
Спасибо! работает как шарм, хотя и прочитал описание для '?' Я не уверен, что понимаю, почему это произведет указанный эффект. - person Yevgeny Simkin; 29.01.2009
comment
Доктор Дредел, это позволяет совпадать с минимальным числом символов. Без него он соответствует как можно большему количеству (что делает его жадным, потому что он занимает так много). - person Evan Fosmark; 29.01.2009
comment
Но это требует много назад. - person Gumbo; 29.01.2009
comment
Нет, нежадные квантификаторы устраняют поиск с возвратом, выполняя некоторую дополнительную работу заранее. - person Alan Moore; 29.01.2009
comment
И какая реализация регулярного выражения делает это? Я провел тест в RegexBuddy со всеми разновидностями регулярных выражений, и всем пришлось вернуться назад, и потребовалось 82 шага, чтобы найти совпадение. - person Gumbo; 29.01.2009
comment
Это .+ в начале регулярного выражения вызывает все возвраты. Но это и то, что в конце, должно быть там только потому, что ОП выполняет «замену», когда он должен выполнять «найти». - person Alan Moore; 29.01.2009
comment
Алан М, что ты имеешь в виду, что я *должен делать находку? Мне нужно, чтобы остальная часть строки (начало и конец подстроки, в которой я нуждаюсь), исчезла... Я не понимаю, о чем вы говорите. - person Yevgeny Simkin; 30.01.2009
comment
Нет, вам не нужно сопоставлять эти части строки. Мне придется опубликовать отдельный ответ, чтобы объяснить (я тоже ударю по возврату). - person Alan Moore; 30.01.2009

Попробуй это:

B=([^;]+);

Это соответствует всему между B= и ;, если только это не ;. Таким образом, он соответствует всему между B= и первым ; после этого.

person Gumbo    schedule 28.01.2009

(Это продолжение разговора из комментариев к ответу Эвана.)

Вот что происходит, когда применяется ваше (исправленное) регулярное выражение: Во-первых, .+ соответствует всей строке. Затем он отступает, отказываясь от большинства только что совпавших символов, пока не дойдет до точки, где B= может совпадать. Затем (.+?) сопоставляет (и фиксирует) все, что видит, пока следующая часть, точка с запятой, не сможет совпасть. Затем последний .+ поглощает оставшиеся символы.

Все, что вас действительно интересует, это "B=" и ";" и что между ними, так зачем сопоставлять остальную часть строки? Единственная причина, по которой вам нужно это сделать, заключается в том, что вы можете заменить всю строку содержимым группы захвата. Но зачем это делать, если вы можете получить прямой доступ к содержимому группы? Вот демонстрация (на Java, потому что я не могу сказать, какой язык вы используете):

String s = "A=abc;B=def_3%^123+-;C=123;";

Pattern p = Pattern.compile("B=(.*?);");
Matcher m = p.matcher(s);
if (m.find())
{
  System.out.println(m.group(1));
}

Зачем «заменять», когда «найти» намного проще? Вероятно, потому что ваш API упрощает задачу; поэтому мы делаем это на Java. Java имеет несколько удобных методов, ориентированных на регулярное выражение, в своем классе String: replaceAll(), replaceFirst(), split() и matches() (который возвращает true, если регулярное выражение соответствует целой строке), но не find(). Также нет удобного способа доступа к группам захвата. Мы не можем сравниться с элегантностью однострочников Perl, например:

print $1 if 'A=abc;B=def_3%^123+-;C=123;' =~ /B=(.*?);/;

...поэтому мы довольствуемся такими хаками:

System.out.println("A=abc;B=def_3%^123+-;C=123;"
    .replaceFirst(".+B=(.*?);.+", "$1"));

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

person Alan Moore    schedule 30.01.2009
comment
Я использую java и меня бесит то, насколько печальны его параметры регулярных выражений по сравнению с perl. 2 другие раздражающие слабости - это отсутствие последней опции / (куда вы вставляете i, g и т. д.) и вместо этого необходимость запускать какую-то причудливую константу .IGNORE_CASE или неприлично - person Yevgeny Simkin; 30.01.2009
comment
уродливая необходимость экранировать все ваши '\' с помощью дополнительных \, что делает регулярное выражение (уже трудное для изучения человеческим глазом) НАМНОГО труднее смотреть. Не говоря уже о том, что если вам нужно запустить строку через несколько регулярных выражений, есть большая вероятность, что результирующая строка потеряет один уровень «\». - person Yevgeny Simkin; 30.01.2009
comment
Я признаю, что я новичок в использовании Regex в Java, но я отмечаю в вашем комментарии ссылку на отсутствие элегантности его использования в perl (с которым я знаком) и склонен полностью согласиться. наконец, - person Yevgeny Simkin; 30.01.2009
comment
с точки зрения дизайна кода исходный пример, предложенный Эваном, намного красивее, хотя и более расточительный с точки зрения цикла. - person Yevgeny Simkin; 30.01.2009
comment
Переход от Perl к Java в любом случае будет болезненным, поскольку Java гораздо более жесткая и многословная. Просто попробуй принять его на своих условиях. Что касается модификаторов, я почти никогда не использую IGNORE_CASE и тому подобное; просто вставьте (?i) в начало самого регулярного выражения. - person Alan Moore; 31.01.2009