Используйте регулярное выражение для поиска кратчайшего возможного совпадения из многострочной строки

#python #regex #string

#python #регулярное выражение #строка

Вопрос:

У меня есть многострочная строка с заданным представлением:

 text1 (arbitrary chars and lines)n
<hr>n
Bitmap: ./media/logo.bmpn
text2 (arbitrary chars and lines)n
text3 (arbitrary chars and lines)n
<hr>n
Bitmap: ./media/logo.bmpn
text2 (arbitrary chars lines)n
n
  

Я хочу сопоставить эту подстроку, которая всегда встречается дважды в строке (один раз всегда в конце):

 <hr>n
Bitmap: ./media/logo.bmpn
text2 (arbitrary chars and lines)n
  

Когда я пытаюсь сопоставить с re.search , он возвращает длинное совпадение:

 regex = re.compile('<hr>n'
                   'Bitmap: [Sn ]*'
                   '$')
print(re.search(regex, string).group())

>> '<hr>nBitmap: ./media/logo.bmpntext2 (arbitrary chars and lines)ntext3 (arbitrary chars and lines)n<hr>nBitmap: ./media/logo.bmpntext2 (arbitrary chars and lines)nn'
  

Можно ли использовать regex для поиска короткого совпадения?

Решение:
поиск с помощью оператора OR возвращает два совпадения (одно длиннее и одно короче):

 regex = re.compile('<hr>n'
                   'Bitmap: [S]*n'
                   '[sS]*?(?=<hr>|nZ)')
print(re.findall(regex, string))
>> ['<hr>nBitmap: ./media/logo.bmpntext2 (arbitrary chars and lines)ntext3 (arbitrary chars and lines)n', '<hr>nBitmap: ./media/logo.bmpntext2 (arbitrary chars lines)n']
  

Комментарии:

1. Сколько совпадений вы хотите получить в общей сложности? И что вы подразумеваете под самым коротким совпадением?

2. Обратите внимание, что сами по себе регулярные выражения не соответствуют самым коротким или самым длинным подстрокам. С re.findall(regex, string) помощью вы получаете все вхождения, и как только они у вас есть, вы можете дополнительно фильтровать совпадения по длине и т.д. Вы также можете получить доступ к последнему совпадению, используя [-1] индекс.

Ответ №1:

Используйте

 (?m)^<hr>r?nBitmap:[sS]*?(?=^<hr>$|Z)
  

Смотрите Доказательство.

Объяснение

 --------------------------------------------------------------------------------
  (?m)                     set flags for this block (with ^ and $
                           matching start and end of line) (case-
                           sensitive) (with . not matching n)
                           (matching whitespace and # normally)
--------------------------------------------------------------------------------
  ^                        the beginning of a "line"
--------------------------------------------------------------------------------
  <hr>                     '<hr>'
--------------------------------------------------------------------------------
  r?                      'r' (carriage return) (optional (matching
                           the most amount possible))
--------------------------------------------------------------------------------
  n                       'n' (newline)
--------------------------------------------------------------------------------
  Bitmap:                  'Bitmap:'
--------------------------------------------------------------------------------
  [sS]*?                 any character of: whitespace (n, r, t,
                           f, and " "), non-whitespace (all but n,
                           r, t, f, and " ") (0 or more times
                           (matching the least amount possible))
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    ^                        the beginning of a "line"
--------------------------------------------------------------------------------
    <hr>                     '<hr>'
--------------------------------------------------------------------------------
    $                        before an optional n, and the end of a
                             "line"
--------------------------------------------------------------------------------
   |                        OR
--------------------------------------------------------------------------------
    Z                       the end of the string
--------------------------------------------------------------------------------
  )                        end of look-ahead
  

Комментарии:

1. Интересно (?!<hr>) , можно ли использовать отрицательный прогноз для исключения первого совпадения и возврата только второго совпадения

2. @user46581 Я не знаю, что вы под этим подразумеваете: просмотры помогают только определить, действительно ли совпадение в определенном месте. (?!<hr>) средства не совпадают в текущем местоположении, если за ним следует <hr>

Ответ №2:

Это работает: <hr>nBitmap:.*n(?:.*n){1,2}

Смотрите: https://regex101.com/r/i64K0W/3

Проблема в вашем регулярном выражении заключалась в * том, что оно жадное.

Комментарии:

1. Ваше регулярное выражение не полностью соответствует первому совпадению, оно состоит из трех строк.

2. Обновил его. Поскольку в вашем примере «Я хочу сопоставить эту подстроку» вы указали только одну строку после «Bitmap», я сопоставил только одну.

3. text2 может иметь произвольное количество строк (OP был обновлен), поэтому это обычно не работает. Лучшим подходом было бы использовать оператор end of string, поскольку подстрока всегда встречается в конце строки

4. Вы правы, решением может быть использование lookahead / lookbehind..