#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 (или любой другой необходимой строки)