Подтвердить что ты не робот

Как я могу выполнять несколько замещений с помощью regex в python?

Я могу использовать этот код ниже для создания нового файла с заменой a на aa с использованием регулярных выражений.

import re

with open("notes.txt") as text:
    new_text = re.sub("a", "aa", text.read())
    with open("notes2.txt", "w") as result:
        result.write(new_text)

Мне было интересно, нужно ли мне использовать эту строку, new_text = re.sub("a", "aa", text.read()), несколько раз, но подставлять строку для других букв, которые я хочу изменить, чтобы изменить более чем одну букву в тексте?

То есть, так aaa, bbb и ccc.

Поэтому мне нужно написать эту строку для всех букв, которые я хочу изменить, или есть более простой способ. Возможно, создать "словарь" переводов. Должен ли я помещать эти буквы в массив? Я не уверен, как позвонить им, если я это сделаю.

4b9b3361

Ответ 1

Ответ, предложенный @nhahtdh, действителен, но я бы сказал, что он менее pythonic, чем канонический пример, который использует код менее непрозрачный, чем его манипуляции с регулярным выражением, и использует преимущества встроенных структур данных и функции анонимной функции python.

В этом контексте имеет смысл словарь переводов. На самом деле, как это делает Python Cookbook, как показано в этом примере (скопировано из ActiveState http://code.activestate.com/recipes/81330-single-pass-multiple-replace/)

import re 

def multiple_replace(dict, text):
  # Create a regular expression  from the dictionary keys
  regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))

  # For each match, look-up corresponding value in dictionary
  return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) 

if __name__ == "__main__": 

  text = "Larry Wall is the creator of Perl"

  dict = {
    "Larry Wall" : "Guido van Rossum",
    "creator" : "Benevolent Dictator for Life",
    "Perl" : "Python",
  } 

  print multiple_replace(dict, text)

Итак, в вашем случае вы можете сделать dict trans = {"a": "aa", "b": "bb"}, а затем передать его в multiple_replace вместе с текстом, который вы хотите перевести. В основном вся эта функция создает одно огромное регулярное выражение, содержащее все ваши регулярные выражения для перевода, а затем, когда его можно найти, передавая лямбда-функцию в regex.sub для выполнения поиска словаря перевода.

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

with open("notes.txt") as text:
    new_text = multiple_replace(replacements, text.read())
with open("notes2.txt", "w") as result:
    result.write(new_text)

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

Как отмечал @nhahtdh, одним из недостатков этого подхода является то, что он не является префиксом: словарные ключи, которые являются префиксами других ключей словаря, вызовут прерывание метода.

Ответ 2

Вы можете использовать группу захвата и обратную ссылку:

re.sub(r"([characters])", r"\1\1", text.read())

Поместите символы, которые вы хотите удвоить, между []. Для случая нижнего регистра a, b, c:

re.sub(r"([abc])", r"\1\1", text.read())

В строке замены вы можете ссылаться на все, что соответствует группе захвата () с обозначением \n, где n - это некоторое положительное целое число (исключено). \1 относится к первой группе захвата. Существует другое обозначение \g<n>, где n может быть любым неотрицательным целым числом (0 разрешено); \g<0> будет ссылаться на весь текст, соответствующий выражению.


Если вы хотите удвоить все символы, кроме новой строки:

re.sub(r"(.)", r"\1\1", text.read())

Если вы хотите удвоить все символы (включая новую строку):

re.sub(r"(.)", r"\1\1", text.read(), 0, re.S)

Ответ 3

Используя советы от как сделать "строгий" класс, мы можем сделать объект идентичным строке, но для дополнительного метода sub:

import re
class Substitutable(str):
  def __new__(cls, *args, **kwargs):
    newobj = str.__new__(cls, *args, **kwargs)
    newobj.sub = lambda fro,to: Substitutable(re.sub(fro, to, newobj))
    return newobj

Это позволяет использовать шаблон построителя, который выглядит лучше, но работает только для предопределенного числа подстановок. Если вы используете его в цикле, больше нет смысла создавать дополнительный класс. Например.

>>> h = Substitutable('horse')
>>> h
'horse'
>>> h.sub('h', 'f')
'forse'
>>> h.sub('h', 'f').sub('f','h')
'horse'

Ответ 4

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

df = pd.DataFrame({'text': ['Billy is going to visit Rome in November', 'I was born in 10/10/2010', 'I will be there at 20:00']})

to_replace=['Billy','Rome','January|February|March|April|May|June|July|August|September|October|November|December', '\d{2}:\d{2}', '\d{2}/\d{2}/\d{4}']
replace_with=['name','city','month','time', 'date']

print(df.text.replace(to_replace, replace_with, regex=True))

И измененный текст:

0    name is going to visit city in month
1                      I was born in date
2                 I will be there at time

Вы можете найти пример здесь

Ответ 5

Я обнаружил, что мне пришлось изменить код Emmett J. Butler, изменив функцию лямбда, чтобы использовать myDict.get(mo.group(1), mo.group(1)). Исходный код не работал у меня; использование myDict.get() также обеспечивает преимущество значения по умолчанию, если ключ не найден.

OIDNameContraction = {
                                'Fucntion':'Func',
                                'operated':'Operated',
                                'Asist':'Assist',
                                'Detection':'Det',
                                'Control':'Ctrl',
                                'Function':'Func'
}

replacementDictRegex = re.compile("(%s)" % "|".join(map(re.escape, OIDNameContraction.keys())))

oidDescriptionStr = replacementDictRegex.sub(lambda mo:OIDNameContraction.get(mo.group(1),mo.group(1)), oidDescriptionStr)