Регулярные выражения не жадные, но все же

У меня есть более крупный текст, который по сути выглядит так:

abc12..manycharshere...hi - abc23...manyothercharshere...jk

Очевидно, есть два элемента, каждый из которых начинается с «abc», интересны числа (12 и 23), а также «привет» и «jk» в конце.

Я хотел бы создать регулярное выражение, которое позволяет мне анализировать числа, но только если совпадают два символа в конце, т.е. я ищу число, связанное с «jk», но следующее регулярное выражение соответствует всей строке и, таким образом, возвращает "12", а не "23" даже при нежадном сопоставлении области со следующим:

abc([0-9]+).*?jk

Есть ли способ создать регулярное выражение, которое соответствует тексту, подобному приведенному выше, то есть получить «23» для элементов, оканчивающихся на «jk»?

В основном мне нужно что-то вроде «сопоставить abc, за которым следует число, но только если в конце есть «jk», прежде чем появится другой экземпляр «abc, за которым следует число»

Примечание: тексты/совпадения являются здесь абстракцией, фактический текст более сложен, особенно то, что может отображаться как «много других символов здесь», я упростил, чтобы более четко показать основную проблему.


person centic    schedule 08.09.2014    source источник
comment
Можете ли вы надежно разделить строку, чтобы разделить сегменты abc...? Скажем по характеру? Что может появиться внутри многих других персонажей здесь? Может ли в нем быть abc?   -  person Ted Hopp    schedule 08.09.2014
comment
Отрицательный взгляд вперед был тем, что я искал, теперь он отлично работает, спасибо!   -  person centic    schedule 08.09.2014
comment
Отрицательный просмотр вперед не будет работать, когда многие другие символы здесь могут содержать букву abc.   -  person Ted Hopp    schedule 08.09.2014
comment
Да, но я могу это исключить, на самом деле я использовал регулярное выражение, которое использует .* впереди, поэтому оно соответствует всему, вплоть до последнего вхождения abc перед jk. Кажется, что это регулярное выражение с большим объемом процессора и большим текстом, но все же завершается за приемлемое время.   -  person centic    schedule 09.09.2014


Ответы (5)


Используйте регулярное выражение, подобное этому. .*abc([0-9]+).*?jk

демонстрация здесь

person TheLostMind    schedule 08.09.2014
comment
На самом деле этот, кажется, делает это наилучшим образом, использование негативного просмотра выше не работало для всех моих случаев... - person centic; 08.09.2014

Я думаю, вы хотите что-то вроде этого,

abc([0-9]+)(?=(?:(?!jk|abc[0-9]).)*jk)

ДЕМО

person Avinash Raj    schedule 08.09.2014

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

abc(?!.*?abc)([0-9]+).*?jk

Демо RegEx

Здесь (?!.*?abc) является отрицательным опережением, которое гарантирует соответствие abc там, где за ним НЕ следует другой abc, таким образом обеспечивая совпадение закрывающей строки между abc и jk.

person anubhava    schedule 08.09.2014

Отсутствие жадности не меняет правила, согласно которому возвращается первое совпадение. Таким образом, abc([0-9]+).*?jk найдет первое jk после «abcчисло», а не последнее, но все равно будет соответствовать первому «abcчислу».

Один из способов решить эту проблему — указать, что точка не должна совпадать с abc([0-9]+):

abc([0-9]+)((?!abc([0-9]+)).)*jk

Если не важно, чтобы весь шаблон был точным совпадением, вы можете сделать это проще:

.*(abc([0-9]+).*?jk)

В этом случае это группа 1, которая содержит предполагаемое совпадение. Шаблон использует жадное сопоставление, чтобы гарантировать, что последнее возможное «abcчисло» совпадает в группе.

person Holger    schedule 08.09.2014

Предполагая, что дефис разделяет «элементы», это регулярное выражение будет захватывать числа из целевого элемента:

abc([0-9]+)[^-]*?jk

См. демонстрацию.

person Bohemian♦    schedule 08.09.2014