Python находит подстроку между определенными символами с помощью regex и replace()

Предположим, что у меня есть строка с множеством случайных вещей в ней, например:

strJunk ="asdf2adsf29Value=five&lakl23ljk43asdldl"

И мне интересно получить подстроку, сидящую между "Value =" и "&", которая в этом примере будет "пять".

Я могу использовать регулярное выражение, как показано ниже:

 match = re.search(r'Value=?([^&>]+)', strJunk)
 >>> print match.group(0)
 Value=five
 >>> print match.group(1)
 five

Как получилось, что match.group(0) - это целое "Value = five", а group (1) - "пять"? И есть ли способ для меня просто получить "пятерку" в качестве единственного результата? (Этот вопрос возникает из-за того, что я имею только небольшое понимание регулярного выражения)

Мне также придется сделать замену в этой строке, например:

 val1 = match.group(1)
 strJunk.replace(val1, "six", 1)    

Что дает:

 'asdf2adsf29Value=six&lakl23ljk43asdldl'

Учитывая, что я планирую выполнить вышеупомянутые две задачи (снова найти строку между 'Value =' и '&', а также заменить это значение), мне было интересно, есть ли другие более эффективные способы поиска подстроки и замены ее в исходной строке. Я прекрасно придерживаюсь того, что у меня есть, но я просто хочу убедиться, что я не занимаю больше времени, чем должен, если будут лучшие методы.

Ответ 1

Именованные группы упрощают получение содержимого группы впоследствии. Компиляция вашего регулярного выражения один раз, а затем повторное использование скомпилированного объекта будет намного более эффективной, чем перекомпиляция для каждого использования (что и происходит при повторном вызове re.search). Вы можете использовать положительные утверждения lookbehind и lookahead, чтобы сделать это регулярное выражение подходящим для подстановки, которую вы хотите сделать.

>>> value_regex = re.compile("(?<=Value=)(?P<value>.*?)(?=&)")
>>> match = value_regex.search(strJunk)
>>> match.group('value')
'five'
>>> value_regex.sub("six", strJunk)
'asdf2adsf29Value=six&lakl23ljk43asdldl'

Ответ 2

Я не совсем уверен, что вы анализируете URL-адреса, и в этом случае вы должны определенно использовать модуль urlparse.

Однако, учитывая, что это не ваш вопрос, возможность разделения на несколько полей с использованием регулярных выражений чрезвычайно высока в Python, поэтому вы должны делать то, что хотите:

import re

strJunk ="asdf2adsf29Value=five&lakl23ljk43asdldl"
split_result = re.split(r'[&=]', strJunk)
split_result[1] = 'six'
print "{0}={1}&{2}".format(*split_result)

Надеюсь, это поможет!

ИЗМЕНИТЬ:

Если вы разделите несколько раз, вы можете использовать re.compile() для компиляции регулярного выражения. Итак, у вас будет:

import re
rx_split_on_delimiters = re.compile(r'[&=]')  # store this somewhere

strJunk ="asdf2adsf29Value=five&lakl23ljk43asdldl"
split_result = rx_split_on_delimiters.split(strJunk)
split_result[1] = 'six'
print "{0}={1}&{2}".format(*split_result)

Ответ 3

Как получилось, что match.group(0) - это целое "Value = five", а group (1) - "пять"? И есть ли способ для меня просто получить "пятерку" в качестве единственного результата? (Этот вопрос возникает из-за того, что я имею только небольшое понимание регулярного выражения)

Я думал, что смотреть за утверждение может помочь вам здесь.

>>> match = re.search(r'(?<=Value=)([^&>]+)', strJunk)
>>> match.group(0)
'five'

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

>>> match = re.search(r'(?<=Value=?)([^&>]+)', strJunk)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/re.py", line 142, in search
    return _compile(pattern, flags).search(string)
  File "/usr/lib/python2.6/re.py", line 245, in _compile
    raise error, v # invalid expression
sre_constants.error: look-behind requires fixed-width pattern

Я не могу сделать это без регулярного выражения. Ваш способ сделать это должен быть быстрее, чем смотреть за утверждение.