Python заменяет несколько строк

Я хотел бы использовать функцию .replace для замены нескольких строк.

Я в настоящее время

string.replace("condition1", "") 

но хотелось бы что-то вроде

 string.replace("condition1", "").replace("condition2", "text") 

хотя это не похоже на хороший синтаксис

Каков правильный способ сделать это? вроде как в grep / regex вы можете сделать \1 и \2 для замены полей на определенные строки поиска

18 Solutions collect form web for “Python заменяет несколько строк”

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

 import re rep = {"condition1": "", "condition2": "text"} # define desired replacements here # use these three lines to do the replacement rep = dict((re.escape(k), v) for k, v in rep.iteritems()) pattern = re.compile("|".join(rep.keys())) text = pattern.sub(lambda m: rep[re.escape(m.group(0))], text) 

Например:

 >>> pattern.sub(lambda m: rep[re.escape(m.group(0))], "(condition1) and --condition2--") '() and --text--' 

Вы могли бы просто сделать небольшую циклическую функцию.

 def replace_all(text, dic): for i, j in dic.iteritems(): text = text.replace(i, j) return text 

где text – это полная строка, а dic – словарь – каждое определение – это строка, которая заменит соответствие термину.

Примечание : в Python 3, iteritems() заменен items()

Осторожно: обратите внимание, что для этого ответа требуется следующее:

  • порядок не имеет отношения к каждой замене
  • это нормально для каждой замены, чтобы изменить результаты предыдущих замещений

Это связано с тем, что словари python не имеют надежного порядка для итерации.

Например, если словарь имеет:

  {«кошка»: «собака», «собака»: «свинья»} 

и строка:

  «Это моя кошка, и это моя собака». 

мы не обязательно знаем, какая запись словаря будет использоваться в первую очередь и будет ли результат:

  «Это моя свинья, и это моя свинья». 

или

  «Это моя собака, и это моя свинья». 

Также хорошо иметь в виду, насколько велика text строка и сколько пар в словаре для повышения эффективности.

Вот вариант первого решения с использованием сокращения, если вам нравится быть функциональным. 🙂

 repls = {'hello' : 'goodbye', 'world' : 'earth'} s = 'hello, world' reduce(lambda a, kv: a.replace(*kv), repls.iteritems(), s) 

еще более хорошая версия martineau:

 repls = ('hello', 'goodbye'), ('world', 'earth') s = 'hello, world' reduce(lambda a, kv: a.replace(*kv), repls, s) 

Я построил это на превосходном ответе FJ:

 import re def multiple_replacer(*key_values): replace_dict = dict(key_values) replacement_function = lambda match: replace_dict[match.group(0)] pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M) return lambda string: pattern.sub(replacement_function, string) def multiple_replace(string, *key_values): return multiple_replacer(*key_values)(string) 

Использование одного снимка:

 >>> replacements = (u"café", u"tea"), (u"tea", u"café"), (u"like", u"love") >>> print multiple_replace(u"Do you like café? No, I prefer tea.", *replacements) Do you love tea? No, I prefer café. 

Обратите внимание, что, поскольку замена выполняется всего за один проход, «кафе» меняется на «чай», но не возвращается к «кафе».

Если вам нужно сделать такую ​​же замену много раз, вы можете легко создать функцию замены:

 >>> my_escaper = multiple_replacer(('"','\\"'), ('\t', '\\t')) >>> many_many_strings = (u'This text will be escaped by "my_escaper"', u'Does this work?\tYes it does', u'And can we span\nmultiple lines?\t"Yes\twe\tcan!"') >>> for line in many_many_strings: ... print my_escaper(line) ... This text will be escaped by \"my_escaper\" Does this work?\tYes it does And can we span multiple lines?\t\"Yes\twe\tcan!\" 

Улучшения:

  • превратил код в функцию
  • добавлена ​​многострочная поддержка
  • исправлена ​​ошибка при выходе
  • легко создать функцию для определенной множественной замены

Наслаждайтесь! 🙂

Я хотел бы предложить использовать строковые шаблоны. Просто поместите строку, которая будет заменена в словаре, и все будет установлено! Пример из docs.python.org

 >>> from string import Template >>> s = Template('$who likes $what') >>> s.substitute(who='tim', what='kung pao') 'tim likes kung pao' >>> d = dict(who='tim') >>> Template('Give $who $100').substitute(d) Traceback (most recent call last): [...] ValueError: Invalid placeholder in string: line 1, col 10 >>> Template('$who likes $what').substitute(d) Traceback (most recent call last): [...] KeyError: 'what' >>> Template('$who likes $what').safe_substitute(d) 'tim likes $what' 

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

 import re def multiple_replace(string, rep_dict): pattern = re.compile("|".join([re.escape(k) for k in rep_dict.keys()]), re.M) return pattern.sub(lambda x: rep_dict[x.group(0)], string) 

Применение:

 >>>multiple_replace("Do you like cafe? No, I prefer tea.", {'cafe':'tea', 'tea':'cafe', 'like':'prefer'}) 'Do you prefer tea? No, I prefer cafe.' 

Если вы хотите, вы можете сделать свои собственные функции замены, начиная с этого более простого.

Мне нужно решение, в котором строки, которые нужно заменить, могут быть регулярными выражениями, например, чтобы помочь нормализовать длинный текст, заменив несколько символов пробелов на один. Основываясь на цепочке ответов от других, включая MiniQuark и mmj, это то, что я придумал:

 def multiple_replace(string, reps, re_flags = 0): """ Transforms string, replacing keys from re_str_dict with values. reps: dictionary, or list of key-value pairs (to enforce ordering; earlier items have higher priority). Keys are used as regular expressions. re_flags: interpretation of regular expressions, such as re.DOTALL """ if isinstance(reps, dict): reps = reps.items() pattern = re.compile("|".join("(?P<_%d>%s)" % (i, re_str[0]) for i, re_str in enumerate(reps)), re_flags) return pattern.sub(lambda x: reps[int(x.lastgroup[1:])][1], string) 

Он работает для примеров, приведенных в других ответах, например:

 >>> multiple_replace("(condition1) and --condition2--", ... {"condition1": "", "condition2": "text"}) '() and --text--' >>> multiple_replace('hello, world', {'hello' : 'goodbye', 'world' : 'earth'}) 'goodbye, earth' >>> multiple_replace("Do you like cafe? No, I prefer tea.", ... {'cafe': 'tea', 'tea': 'cafe', 'like': 'prefer'}) 'Do you prefer tea? No, I prefer cafe.' 

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

 >>> s = "I don't want to change this name:\n Philip II of Spain" >>> re_str_dict = {r'\bI\b': 'You', r'[\n\t ]+': ' '} >>> multiple_replace(s, re_str_dict) "You don't want to change this name: Philip II of Spain" 

Если вы хотите использовать ключи словаря как обычные строки, вы можете избежать их перед вызовом multiple_replace, используя, например, эту функцию:

 def escape_keys(d): """ transform dictionary d by applying re.escape to the keys """ return dict((re.escape(k), v) for k, v in d.items()) >>> multiple_replace(s, escape_keys(re_str_dict)) "I don't want to change this name:\n Philip II of Spain" 

Следующая функция может помочь в поиске ошибочных регулярных выражений среди ваших ключей словаря (поскольку сообщение об ошибке из multiple_replace не очень важно):

 def check_re_list(re_list): """ Checks if each regular expression in list is well-formed. """ for i, e in enumerate(re_list): try: re.compile(e) except (TypeError, re.error): print("Invalid regular expression string " "at position {}: '{}'".format(i, e)) >>> check_re_list(re_str_dict.keys()) 

Обратите внимание, что он не связывает замены, а выполняет их одновременно. Это делает его более эффективным, не сдерживая того, что он может сделать. Чтобы подражать эффекту цепочки, вам просто нужно добавить дополнительные пары замены строк и обеспечить ожидаемый порядок пар:

 >>> multiple_replace("button", {"but": "mut", "mutton": "lamb"}) 'mutton' >>> multiple_replace("button", [("button", "lamb"), ... ("but", "mut"), ("mutton", "lamb")]) 'lamb' 

В моем случае мне нужна простая замена ключей с именами, поэтому я подумал:

 a = 'this is a test string' b = {'i': 'Z', 's': 'Y'} for x,y in b.items(): a = a.replace(x, y) >>> a 'thZY ZY a teYt YtrZng' 

Вот мои $ 0,02. Он основан на ответе Эндрю Кларка, немного более понятным, и он также охватывает случай, когда заменяемая строка является подстрокой другой строки для замены (более длинные выигрыши строк)

 def multireplace(string, replacements): """ Given a string and a replacement map, it returns the replaced string. :param str string: string to execute replacements on :param dict replacements: replacement dictionary {value to find: value to replace} :rtype: str """ # Place longer ones first to keep shorter substrings from matching # where the longer ones should take place # For instance given the replacements {'ab': 'AB', 'abc': 'ABC'} against # the string 'hey abc', it should produce 'hey ABC' and not 'hey ABc' substrs = sorted(replacements, key=len, reverse=True) # Create a big OR regex that matches any of the substrings to replace regexp = re.compile('|'.join(map(re.escape, substrs))) # For each match, look up the new string in the replacements return regexp.sub(lambda match: replacements[match.group(0)], string) 

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

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

 >>> replacements = {'cond1':'text1', 'cond2':'text2'} >>> cmd = 'answer = s' >>> for k,v in replacements.iteritems(): >>> cmd += ".replace(%s, %s)" %(k,v) >>> exec(cmd) 

Теперь answer – результат всех замен в свою очередь

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

Вот пример, который более эффективен для длинных строк со многими небольшими заменами.

 source = "Here is foo, it does moo!" replacements = { 'is': 'was', # replace 'is' with 'was' 'does': 'did', '!': '?' } def replace(source, replacements): finder = re.compile("|".join(re.escape(k) for k in replacements.keys())) # matches every string we want replaced result = [] pos = 0 while True: match = finder.search(source, pos) if match: # cut off the part up until match result.append(source[pos : match.start()]) # cut off the matched part and replace it in place result.append(replacements[source[match.start() : match.end()]]) pos = match.end() else: # the rest after the last match result.append(source[pos:]) break return "".join(result) print replace(source, replacements) 

Дело в том, чтобы избежать многих конкатенаций длинных строк. Мы разделяем исходную строку на фрагменты, заменяя некоторые фрагменты по мере формирования списка, а затем присоединяем все это обратно к строке.

Или просто для быстрого взлома:

 for line in to_read: read_buffer = line stripped_buffer1 = read_buffer.replace("term1", " ") stripped_buffer2 = stripped_buffer1.replace("term2", " ") write_to_file = to_write.write(stripped_buffer2) 

Вот еще один способ сделать это со словарем:

 listA="The cat jumped over the house".split() modify = {word:word for number,word in enumerate(listA)} modify["cat"],modify["jumped"]="dog","walked" print " ".join(modify[x] for x in listA) 

Начиная с драгоценного ответа Андрея, я разработал сценарий, который загружает словарь из файла и разрабатывает все файлы в открытой папке для замены. Сценарий загружает сопоставления из внешнего файла, в котором вы можете установить разделитель. Я новичок, но я нашел этот сценарий очень полезным при выполнении нескольких подстановок в нескольких файлах. Он загрузил словарь с более чем 1000 записей за считанные секунды. Это не изящно, но это сработало для меня

 import glob import re mapfile = input("Enter map file name with extension eg. codifica.txt: ") sep = input("Enter map file column separator eg. |: ") mask = input("Enter search mask with extension eg. 2010*txt for all files to be processed: ") suff = input("Enter suffix with extension eg. _NEW.txt for newly generated files: ") rep = {} # creation of empy dictionary with open(mapfile) as temprep: # loading of definitions in the dictionary using input file, separator is prompted for line in temprep: (key, val) = line.strip('\n').split(sep) rep[key] = val for filename in glob.iglob(mask): # recursion on all the files with the mask prompted with open (filename, "r") as textfile: # load each file in the variable text text = textfile.read() # start replacement #rep = dict((re.escape(k), v) for k, v in rep.items()) commented to enable the use in the mapping of re reserved characters pattern = re.compile("|".join(rep.keys())) text = pattern.sub(lambda m: rep[m.group(0)], text) #write of te output files with the prompted suffice target = open(filename[:-4]+"_NEW.txt", "w") target.write(text) target.close() 

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

 def mass_replace(text, dct): new_string = "" old_string = text while len(old_string) > 0: s = "" sk = "" for k in dct.keys(): if old_string.startswith(k): s = dct[k] sk = k if s: new_string+=s old_string = old_string[len(sk):] else: new_string+=old_string[0] old_string = old_string[1:] return new_string print mass_replace("The dog hunts the cat", {"dog":"cat", "cat":"dog"}) 

это станет The cat hunts the dog

Другой пример: Список ввода

 error_list = ['[br]', '[ex]', 'Something'] words = ['how', 'much[ex]', 'is[br]', 'the', 'fish[br]', 'noSomething', 'really'] 

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

 words = ['how', 'much', 'is', 'the', 'fish', 'no', 'really'] 

Код:

 [n[0][0] if len(n[0]) else n[1] for n in [[[w.replace(e,"") for e in error_list if e in w],w] for w in words]] 

Я не знаю о скорости, но это мое быстрое решение:

 reduce(lambda a, b: a.replace(*b) , [('o','W'), ('t','X')] #iterable of pairs: (oldval, newval) , 'tomato' #The string from which to replace values ) 

… но мне нравится ответ # 1 регулярного выражения выше. Примечание. Если одно новое значение является подстрокой другого, то операция не является коммутативной.

Почему не такое решение?

 s = "The quick brown fox jumps over the lazy dog" for r in (("brown", "red"), ("lazy", "quick")): s = s.replace(*r) 
Interesting Posts

Django: Значение ведущего подчеркивания в списке кортежей, используемых для определения полей выбора?

Мой Django устанавливает в виртуальном env отсутствие папки шаблонов администраторов

Python: двухкристальный гауссовский фитинг с нелинейными наименьшими квадратами

Ширина линии matplotlib при сохранении PDF-файла

Запуск нескольких пауков один за другим

Использование переменных в обработчике сигналов – требуется глобальное?

Почему str.count ('') и len (str) дают разные результаты?

Как преобразовать объект datetime в миллисекунды с эпохи (unix time) в Python?

Subprocess.Popen зависает с интерактивными программами при вызове изнутри Django

изменение оператора ** на силовую функцию с помощью синтаксического анализа?

Подключение к удаленному экземпляру IPython

sys.argv как байты в Python 3k

Разархивировать zip-файлы в python

Что означает «понимание списка»? Как это работает и как я могу его использовать?

Numpy: разделите каждую строку на векторный элемент

Python - лучший язык программирования в мире.