Замена разных подстрок без четкого шаблона в python

#python #string #replace

#python #строка #заменить

Вопрос:

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

 query = """ SELECT DATE(utimestamp) as utimestamp, sum(value) as value 
from table 
where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00' 
group by YEAR(utimestamp), MONTH(utimestamp), id """
  

Я хочу заменить часть, касающуюся даты, после group by .

Эта часть может быть любой из следующих строк:

 'YEAR(utimestamp), MONTH(utimestamp), DAY(utimestamp),'
'YEAR(utimestamp), MONTH(utimestamp), WEEK(utimestamp),'
'YEAR(utimestamp), MONTH(utimestamp),'
'YEAR(utimestamp),'
  

Моя идея состоит в том, чтобы выполнить поиск «(utimestamp)» и получить часть слева (ГОД, ДЕНЬ, НЕДЕЛЯ или МЕСЯЦ) в поисках первого пробела слева. После их удаления я хочу вставить другую подстроку, но как я могу вставить эту подстроку теперь, когда у меня есть пробелы, куда должна идти новая подстрока.

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

Есть ли более простой и аккуратный способ сделать это? Я что-то упускаю?

ПРИМЕР:

Введите строку, которая нуждается в замене:

query = «»» ВЫБЕРИТЕ ДАТУ (utimestamp) в качестве utimestamp, сумму (значение) в качестве значения из таблицы, где utimestamp МЕЖДУ ‘2000-06-28 00:00:00’ И ‘2000-07-05 00:00:00’ группируется по ГОДУ (utimestamp), МЕСЯЦУ (utimestamp), идентификатору «»»

или

 query = """ SELECT DATE(utimestamp) as utimestamp, sum(value) as value 
        from table 
        where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00' 
        group by YEAR(utimestamp), id """
  

или

 query = """ SELECT DATE(utimestamp) as utimestamp, sum(value) as value 
        from table 
        where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00' 
        group by YEAR(utimestamp), MONTH(utimestamp), WEEK(utimestamp), id """
  

и т.д.

Желаемый результат:

 query_replaced = """ SELECT DATE(utimestamp) as utimestamp, sum(value) as value 
    from table 
    where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00' 
    group by MY_COOL_STRING, id """
  

Если должно работать для всех этих случаев (и более, указанных ранее)

Следуя ответу @Efferalgan, я придумал это:

 query_1 = query.split("group by")[0]
utimestamp_list = query.split("(utimestamp)")
l = len(utimestamp_list)
query_2 = utimestamp_list[l-1]
query_3 = query_1   " group by MY_COOL_STRING"   query_2
  

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

1. Не query = query.split("group by")[0] "group by" whatever_text_you_want делает то, что вы хотите? Или я неправильно понял ваш вопрос?

2. Ну, теперь, когда вы это сказали, я мог бы сделать это таким образом. Мне нужно добавить последнюю часть в конце (в данном случае ‘id’).

3. Возможно, полный пример поможет людям точно понять, чего вы хотите.

Ответ №1:

Из того, что вы спросили, я бы выбрал

 query = query.split("group by")[0]   " group by MY_COOL_STRING"   query.split("(utimestamp)")[-1]
  

Он объединяет часть перед group by , затем MY_COOL_STRING и затем первым делом перед первым (utimestamp) .

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

1. Проблема в том, что это не просто идентификатор, который я мог бы получить в конце запроса, я мог бы получить, например, «id, order by utimestamp asc».

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

3. Отлично, спасибо! Было бы здорово, если бы вы могли отредактировать свой ответ, чтобы я мог его принять.

Ответ №2:

Если я не ошибаюсь, вы не хотите избавляться от (utimestamp) части, только от YEAR MONTH , и т.д. Или, может быть, я ошибся, но это решение тривиально для адаптации в этом случае: просто адаптируйте rep dict для удовлетворения ваших потребностей.

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

 import re

rep = {
    'YEAR': 'y',
    'MONTH': 'm',
    'WEEK': 'w',
    'DAY': 'd',
}

query = """ SELECT DATE(utimestamp) as utimestamp, sum(value) as value from table
where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00'
group by YEAR(utimestamp), MONTH(utimestamp), id """

rep = dict((re.escape(k), v) for k, v in rep.iteritems())
pattern = re.compile("|".join(rep.keys()))
replaced = pattern.sub(lambda m: rep[re.escape(m.group(0))], query)

print("Processed query: {}n".format(replaced))
  

Это всего лишь базовый пример. Вот более полный вариант с комментариями, объясняющими, что делает код, включая тест в конце для всех возможных шаблонов, которые вы упомянули:

 import re

# Several possible patterns like you mentioned.
# Only used for testing further down.
patterns = [
    'YEAR(utimestamp), MONTH(utimestamp), DAY(utimestamp)',
    'YEAR(utimestamp), MONTH(utimestamp), WEEK(utimestamp)',
    'YEAR(utimestamp), MONTH(utimestamp)',
    'YEAR(utimestamp)'
]

# These are the several patterns to be matched and their replacements.
# The keys are the patterns to match and the values are what you want
# to replace them with.
rep = {
    'YEAR': 'y',
    'MONTH': 'm',
    'WEEK': 'w',
    'DAY': 'd',
}

# The query string template, where we'll replace {} with each of the patterns.
query = """ SELECT DATE(utimestamp) as utimestamp, sum(value) as value from table
where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00'
group by {}, id """

# A dictionary with escaped patterns (the keys) suitable for use in regex.
rep = dict((re.escape(k), v) for k, v in rep.iteritems())

# We join each possible pattern (the keys in the rep dict) with | so that the
# regex engine considers them all when matching, i.e., "hey, regex engine,
# please match YEAR or MONTH or WEEK or DAY". This builds the matching patter
# we'll use and we also pre-compile the regex to make it faster.
pattern = re.compile("|".join(rep.keys()))

# This is the trick part: we're using pattern.sub() to replace our pattern from
# above with what we want (the values in the rep dict). We're telling the regex
# engine to call a function for each occurrence of the pattern in order to get
# the value we're replacing it with. In our case, we want to get the value from
# the rep dict, using the key which is the found match. m is the match object,
# m.group(0) is the first match, re.escape() escapes the value and we finally
# use this as the key to fetch the value from the rep dict.
q = query.format(patterns[0])
print("Query: {}n".format(q))
replaced = pattern.sub(lambda m: rep[re.escape(m.group(0))], q)
print("Processed query: {}n".format(replaced))

# Now to test it with the examples you gave let's iterate over the patterns
# dict, form a new query string using each of them and run the regex against
# each one.
print("###########################")
print("Test each pattern:n")
print("---------------------------")
for p in patterns:
    q = query.format(p)
    print("Pattern: {}".format(p))
    print("Original query: {}n".format(q))

    replaced = pattern.sub(lambda m: rep[re.escape(m.group(0))], q)
    print("Processed query: {}n".format(replaced))
    print("---------------------------n")
  

Вы можете прочитать больше о том, как re.sub() это работает.

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

1. Я добавил пример, который мог бы объяснить это лучше.

Ответ №3:

Для этого вы можете использовать re.sub() регулярное выражение:

 >>> import re
>>> replace_with = 'HELLO'
>>> new_string  = re.sub('group bysw (utimestamp)', "group_by" replace_with, query)

# Value of new_string: SELECT  as utimestamp, sum(value) as value 
# from table 
# where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00' 
# group by HELLO, HELLO, id
  

где replace_with находится содержимое, которое вам нужно обновить с помощью шаблона 'w (utimestamp)' , и query строка, которую вы упомянули в коде.

Здесь w означает алфавиты с вхождением одного или нескольких, тогда (utimestamp) как наряду с этим обозначает слова, за которыми следует строка (utimestamp) .

Редактировать:

Как упомянуто в комментарии, для замены всех экземпляров timestamp в query , выражение регулярного выражения должно иметь вид:

 re.sub('group bysw (utimestamp)(,s*w (utimestamp))*', "group_by"   replace_with, query)

# Returned Value:  
# SELECT DATE(utimestamp) as utimestamp, sum(value) as value from table
# where utimestamp BETWEEN '2000-06-28 00:00:00' AND '2000-07-05 00:00:00'
# group by HELLO, id
  

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

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

2. Результат, который я ищу: ВЫБЕРИТЕ как utimestamp, sum(value) как значение из таблицы, где utimestamp МЕЖДУ ‘2000-06-28 00:00:00’ И ‘2000-07-05 00:00:00’ группируется по HELLO, id Просто удалите все совпадения слов, за которыми следует ‘(utimestamp)’ и заменитес помощью HELLO (или любой другой необходимой строки)