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

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

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

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:

Ответы [ 3 ]

7 голосов
/ 29 января 2009

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

".+B=(.+?);.+" 
5 голосов
/ 29 января 2009

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

B=([^;]+);

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

2 голосов
/ 30 января 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"));

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

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