문자열의 여러 하위 문자열을 바꾸는 방법은 무엇입니까?


284

.replace 함수를 사용하여 여러 문자열을 바꾸고 싶습니다.

나는 현재

string.replace("condition1", "")

하지만 같은 것을 갖고 싶습니다

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

좋은 문법처럼 보이지는 않지만

이를 수행하는 올바른 방법은 무엇입니까? grep / regex에서 어떻게 할 수 \1있고 \2필드를 특정 검색 문자열로 바꾸는 것과 같은 종류


7
제공된 모든 솔루션을 사용해 보셨습니까? 어느 것이 더 빠릅니까?
tommy.carstensen 2016 년

다른 시나리오에서 모든 답변을 테스트하는 데 시간을 들였습니다. 참조 stackoverflow.com/questions/59072514/...
파블로

1
솔직히, 나는 다른 모든 것에 대한 당신의 연쇄 접근을 선호합니다. 나는 해결책을 찾는 동안 여기에 도착했고 당신의 것을 사용했고 그것은 잘 작동합니다.
frakman1

@ frakman1 +1. 왜 이것이 더 많이지지되지 않는지 전혀 모른다. 다른 모든 방법은 코드를 읽기 어렵게 만듭니다. 교체 할 함수 전달 배열이 있으면 작동합니다. 그러나 귀하의 체인 방식은 가장 명확합니다 (적어도 정적 인 교체 횟수로)
IceFire

답변:


269

다음은 정규 표현식으로 트릭을 수행해야하는 간단한 예입니다.

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()) 
#Python 3 renamed dict.iteritems to dict.items so use rep.items() for latest versions
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--'

7
교체는 단일 패스로 이루어집니다.
Andrew Clark

26
dkamins : 너무 영리하지도 않고 영리하지도 않습니다 ( "|"로 키를 결합하기 전에 키를 정규식으로 이스케이프해야합니다). 왜 그렇게 과도하게 설계되지 않았습니까? 이런 식으로 우리가 한 번에 그것을 할 수 있기 때문에 같은 충돌을 피하고, (빠른 =), 우리는 동시에 모든 교체 할 수 "spamham sha".replace("spam", "eggs").replace("sha","md5")있는 "eggmd5m md5"대신"eggsham md5"
양 비행

8
@AndrewClark 람다로 마지막 줄에서 일어나는 일을 설명 할 수 있다면 크게 감사하겠습니다.
미네랄

11
안녕하세요,이 스 니펫의 명확한 버전으로 작은 요점을 만들었습니다. 또한 조금 더 효율적이어야한다 : gist.github.com/bgusach/a967e0587d6e01e889fd1d776c5f3729
bgusach

15
파이썬 3의 경우 iteritems () 대신 items ()를 사용하십시오.
Jangari

127

멋진 작은 루핑 기능을 만들 수 있습니다.

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

여기서 text완전한 문자열 dic은 사전이며 각 정의는 용어와 일치하는 문자열을 대체합니다.

참고 : Python 3에서는 다음 iteritems()으로 대체되었습니다.items()


주의 : 파이썬 사전은 신뢰할만한 반복 순서가 없습니다. 이 솔루션은 다음과 같은 경우에만 문제를 해결합니다.

  • 교체 순서는 관련이 없습니다.
  • 교체가 이전 교체의 결과를 변경해도 괜찮습니다.

예를 들어 :

d = { "cat": "dog", "dog": "pig"}
my_sentence = "This is my cat and this is my dog."
replace_all(my_sentence, d)
print(my_sentence)

가능한 출력 # 1 :

"이것은 나의 돼지이고 이것은 나의 돼지입니다."

가능한 출력 # 2

"이것은 나의 개이고 이것은 나의 돼지입니다."

하나의 가능한 수정은 OrderedDict를 사용하는 것입니다.

from collections import OrderedDict
def replace_all(text, dic):
    for i, j in dic.items():
        text = text.replace(i, j)
    return text
od = OrderedDict([("cat", "dog"), ("dog", "pig")])
my_sentence = "This is my cat and this is my dog."
replace_all(my_sentence, od)
print(my_sentence)

산출:

"This is my pig and this is my pig."

주의 # 2 :text 문자열이 너무 크거나 사전에 많은 쌍이있는 경우 비효율적 입니다.


37
다른 교체를 적용하는 순서는 중요하므로 표준 dict을 사용하는 대신 OrderedDict-또는 2- 튜플 목록을 사용하는 것이 좋습니다.
slothrop 2016 년

5
이렇게하면 문자열을 두 번 반복 할 수 있습니다 ... 성능에는 좋지 않습니다.
Valentin Lorentz

6
성능면에서 Valentin의 말보다 나쁩니다. dic에있는 항목 수만큼 텍스트를 순회합니다! '텍스트'가 작지만 큰 텍스트에는 끔찍한 경우 좋습니다.
JDonner

3
이것은 어떤 경우에는 좋은 해결책입니다. 예를 들어, 나는 2 자 이하로 바꾸고 싶습니다. 대체 키가 어떤 값과도 일치하지 않기 때문에 입력 순서를 신경 쓰지 않습니다. 그러나 나는 무슨 일이 일어나고 있는지 분명히하고 싶습니다.
Nathan Garabedian

5
첫 번째 반복에서 새로 삽입 된 텍스트를 두 번째 반복에서 일치시킬 수 있기 때문에 예기치 않은 결과가 발생할 수 있습니다. 예를 들어, 모든 'A'를 'B'로, 모든 'B'를 'C'로 순진하게 바꾸려고하면 문자열 'AB'가 'BC'가 아닌 'CC'로 변환됩니다.
Ambroz Bizjak

106

왜 이런 해결책이 없습니까?

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

#output will be:  The quick red fox jumps over the quick dog

2
이것은 매우 유용하고 간단하며 이식 가능합니다.
파쇄

멋지게 보였지만 다음과 같이 정규 표현식을 바꾸지 않았습니다 : r in ((r '\ s.', '.'), (r '\ s,', ',')) :
Martin

2
1- 라이너로 만들려면 : ss = [( "갈색", "빨간색"), ( "게으른", "빠른")에서 r에 대한 s.replace (* r)] [0]
Mark K

95

다음은 기능을 좋아하는 경우 reduce를 사용하는 첫 번째 솔루션의 변형입니다. :)

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

마르티노의 더 나은 버전 :

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

8
repls튜플 시퀀스 를 만들고 iteritems()통화를 없애는 것이 더 간단합니다 . 즉, repls = ('hello', 'goodbye'), ('world', 'earth')reduce(lambda a, kv: a.replace(*kv), repls, s). 파이썬 3에서도 변경되지 않은 상태로 작동합니다.
martineau

좋은! python3을 사용하는 경우 iteritems 대신 항목을 사용하십시오 (현재 dicts stuff에서 제거됨).
e.arbitrio

2
@ martineau : python3 reduce에서 제거 된 이후로 변경되지 않은 것은 사실이 아닙니다 .
normanius

5
@normanius : reduce아직도 그러나 그것은의 일부가되었다 존재 functools모듈합니다 (참조 문서를 내가 변하지 말했다 때, 나는 동일한 코드를 실행 -하지만 수 알듯이 그 필요 의미, 파이썬 3) reduce이었다 import필요한 경우 에드 더 이상 내장되어 있지 않기 때문입니다.
martineau

35

이것은 FJ와 MiniQuark의 훌륭한 답변을 간결하게 요약 한 것입니다. 여러 개의 동시 문자열 대체 를 달성하기 위해 필요한 것은 다음 기능입니다.

def multiple_replace(string, rep_dict):
    pattern = re.compile("|".join([re.escape(k) for k in sorted(rep_dict,key=len,reverse=True)]), flags=re.DOTALL)
    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.'

원하는 경우이 간단한 것부터 시작하여 고유 한 전용 교체 기능을 만들 수 있습니다.


1
이것이 좋은 솔루션이지만 동시 문자열 교체는 순차적으로 수행하는 것과 동일한 결과를 제공하지는 않지만 중요하지는 않습니다.
martineau

2
물론 rep_dict = {"but": "mut", "mutton": "lamb"}문자열을 사용 "button"하면 "mutton"코드가 생성되지만 "lamb"교체품이 체인으로 연결되어 있는지 확인하십시오.
martineau

2
이것이이 코드의 주요 기능이며 결함이 아닙니다. 체인으로 대체하면 내 예에서와 같이 두 단어를 동시에 그리고 상호 대체하는 원하는 동작을 얻을 수 없습니다.
mmj

1
필요하지 않으면 훌륭한 기능으로 보이지 않습니다. 그러나 여기서 우리는 동시 교체 에 대해 이야기 하고 있으며 실제로 주요 기능입니다. "체인 된"대체를 사용하면 예제의 출력 Do you prefer cafe? No, I prefer cafe.은 바람직하지 않습니다.
mmj


29

나는 이것을 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é.

교체는 한 번만 수행되므로 "café"는 "tea"로 변경되지만 "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!\"

개량:

  • 코드를 함수로 바꿨다
  • 여러 줄 지원 추가
  • 탈출 버그 수정
  • 특정 복수 교체를위한 기능을 쉽게 생성

즐겨! :-)


1
어떤 사람이 나와 같은 파이썬 멍청한 놈에 대해이 단계별로 설명 할 수 있습니까?
줄리안 레즈

여기에 파이썬 멍청한 놈이 있습니다. 그래서 그것을 이해하는데 불완전한 샷을하겠습니다 .. a. key_values를 대체 할 스터프 ( "|"로 결합 된 키)와 논리 (일치가 키인 경우 리턴 값)로 나눕니다. b. 정규 표현식 파서를 만든다 (키를 찾고 주어진 논리를 사용하는 "패턴")-이것을 람다 함수로 감싸서 리턴한다. 내가 지금 찾고있는 것들 : re.M, 그리고 교체 로직을위한 람다의 필요성.
Fox

1
@ 폭스 당신은 그것을 얻었다. 람다를 사용하는 대신 함수를 정의 할 수 있습니다. 코드를 짧게 만드는 것입니다. 그러나 pattern.sub하나의 매개 변수 (텍스트를 바꿀 텍스트) 만있는 함수가 필요하므로이 함수에 액세스 할 수 있어야합니다 replace_dict. re.M여러 줄 대체를 허용합니다 ( docs.python.org/2/library/re.html#re.M 에 잘 설명되어 있습니다 ).
MiniQuark

22

문자열 템플릿의 사용법을 제안하고 싶습니다. 문자열을 사전에 대치하면 모든 것이 설정됩니다! 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'

좋아 보이지만 키를 제공하지 않으면 substitute예외가 발생하므로 사용자로부터 템플릿을 가져올 때주의하십시오.
Bart Friederichs

2
이 방법의 단점은 대체 할 $ strings를 템플릿에 모두 포함해야한다는 것입니다. 여기를
RolfBly

17

필자의 경우 고유 키를 이름으로 간단히 바꾸어야했기 때문에 다음과 같이 생각했습니다.

a = 'This is a test string.'
b = {'i': 'I', 's': 'S'}
for x,y in b.items():
    a = a.replace(x, y)
>>> a
'ThIS IS a teSt StrIng.'

3
교체 충돌이없는 한 작동합니다. 당신이 교체 한 경우 is당신은 이상한 행동을 얻을 것입니다.
bgusach

1
순서가 중요한 경우 위의 지시 대신 배열을 사용할 수 있습니다. b = [ ['i', 'Z'], ['s', 'Y'] ]; for x,y in (b): a = a.replace(x, y) 그런 다음 배열 쌍을 조심스럽게 주문하면 replace ()를 재귀 적으로 사용하지 않도록 할 수 있습니다.
코드 리드

dicts는 이제 Python 3.7.0부터 순서를 유지 하는 것으로 보입니다 . 테스트를 거쳤으며 안정적인 최신 Python 3을 사용하는 컴퓨터에서 순서대로 작동합니다.
James Koss

15

시작 Python 3.8할당 표현식 (PEP 572) ( :=연산자) 도입을 통해 목록 이해 내에서 대체를 적용 할 수 있습니다.

# text = "The quick brown fox jumps over the lazy dog"
# replacements = [("brown", "red"), ("lazy", "quick")]
[text := text.replace(a, b) for a, b in replacements]
# text = 'The quick red fox jumps over the quick dog'

루프에서 바꾸기를 사용하는 것보다 이것이 효율적인지 알고 있습니까? 성능에 대한 모든 답변을 테스트하고 있지만 아직 3.8이 없습니다.
Pablo

왜 출력을 목록으로 가져 옵니까?
johnrao07

1
@ johnrao07 글쎄요 목록 이해력은 목록을 만듭니다. 이것이 바로이 경우에 당신이 얻는 이유 ['The quick red fox jumps over the lazy dog', 'The quick red fox jumps over the quick dog']입니다. 그러나 대입 식 ( text := text.replace)도 새로운 버전을 text변경하여 반복적으로 빌드 합니다. 목록 이해 후에 text수정 된 텍스트가 포함 된 변수를 사용할 수 있습니다 .
Xavier Guihot

1
새로운 버전의 text단일 라이너 를 반환 하려면 목록 이해의 마지막 요소를 추출하는 [text := text.replace(a, b) for a, b in replacements][-1](참고 [-1])를 사용할 수도 있습니다 . 즉,의 마지막 버전입니다 text.
Xavier Guihot

13

여기 내 $ 0.02. Andrew Clark의 답변을 기반으로하고 약간 더 명확하며 대체 할 문자열이 바꿀 다른 문자열의 하위 문자열 인 경우도 포함합니다 (더 긴 문자열 승리)

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)

그것은이에 이 요점 , 당신이 어떤 제안이있는 경우 수정 주시기 바랍니다.


1
정규식은 모든 키에서 길이 순서로 내림차순으로 정렬하고 | 정규식 대체 연산자. 그리고 대안이 있다면 가능한 한 가장 긴 선택이 선택되도록 정렬이 필요합니다.
Sachin S

정렬 덕분에 이것이 최선의 해결책이라는 데 동의합니다. 정렬 외에도 원래의 대답과 동일하므로 아무도 중요한 기능을 놓치지 않도록 솔루션에 대한 정렬을 빌 렸습니다.
mmj 2016 년

6

예를 들어 여러 공백 문자를 단일 문자로 바꾸어 긴 텍스트를 정규화하는 데 도움이되는 대체 문자열이 정규식이 될 수있는 솔루션이 필요했습니다. 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'

감사합니다. 대체에 역 참조를 사용할 수 있도록 개선 할 수 있습니까? 나는 그것을 추가하는 방법을 즉시 알아 내지 못했습니다.
cmarqu

위의 질문에 대한 답변은 stackoverflow.com/questions/45630940/…
cmarqu

4

다음은 작은 교체가 많은 긴 문자열에서 더 효율적인 샘플입니다.

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)

요점은 긴 줄의 많은 연결을 피하는 것입니다. 소스 문자열을 조각으로 자르고 목록을 만들 때 일부 조각을 대체 한 다음 전체를 문자열로 다시 결합합니다.


2

당신은 정말로 이런 식으로하지 말아야하지만 너무 멋지다.

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

이제 answer모든 교체의 결과는

다시 말하지만, 이것은 매우 해킹이며 정기적으로 사용해야하는 것이 아닙니다. 그러나 필요한 경우 이와 같은 작업을 수행 할 수 있다는 것을 아는 것이 좋습니다.


2

나는이 문제로 어려움을 겪고 있었다. 많은 치환으로 정규 표현식이 어려움을 겪고 있으며 string.replace(실험 조건에서) 루핑보다 약 4 배 느립니다 .

반드시 Flashtext 라이브러리 ( 블로그 게시물 here , Github here )를 사용해보십시오 . 내 경우 는 살짝 넘어했다 , 2 차의 크기는 0.015의 1.8의에서, 빠르게 (정규 표현식 7.7의했다) 각 문서에 대해.

위의 링크에서 사용 예를 쉽게 찾을 수 있지만 다음은 실제 예입니다.

    from flashtext import KeywordProcessor
    self.processor = KeywordProcessor(case_sensitive=False)
    for k, v in self.my_dict.items():
        self.processor.add_keyword(k, v)
    new_string = self.processor.replace_keywords(string)

Flashtext는 단일 패스 ( 'a'를 'c'로 변환 하는 a- > bb-> c 를 피하기 위해) 대체 합니다. Flashtext는 또한 전체 단어를 찾습니다 ( 'is'는 'th is ' 와 일치하지 않습니다 ). 대상이 여러 단어이면 'Hello'가 'This is'로 바뀌면 정상적으로 작동합니다.


HTML 태그를 교체해야하는 경우 어떻게 작동합니까? 예 교체 <p>와 함께 /n. 귀하의 접근 방식을 시도했지만 태그가있는 플래시 텍스트가 구문 분석하지 않는 것 같습니다.
alias51

1
왜 예상대로 작동하지 않는지 잘 모르겠습니다. 한 가지 가능성은 이러한 태그가 공백으로 구분되지 않으며 Flashtext가 전체 단어를 찾는다는 것을 기억하십시오. 이를 해결하는 방법은 간단한 바꾸기를 먼저 사용하여 "Hi <p> ​​there"가 "Hi <p> ​​there"가되도록하는 것입니다. 완료되면 원하지 않는 공간을 제거하기 위해주의를 기울여야합니다 (또한 간단하게 교체 하시겠습니까?). 희망이 도움이됩니다.
파블로

고마워, 당신 은 단어의 끝 을 설정 <하고 >표시 할 수 있습니까 (그러나 바꾸기에 포함)?
alias51

1
"단어"는 공백으로 만 표시됩니다. "KeywordProcessor"에서 설정할 수있는 선택적 매개 변수가있을 수 있습니다. 그렇지 않으면 위의 접근 방식을 고려하십시오. "<"를 "<"로 대체하고 Flashtext를 적용한 다음 대체하십시오 (예를 들어 "" "를"< "로,"\ n "을"\ n "으로 작동).
파블로

2

나는이 질문에 완전성을 위해 단일 라인 재귀 람다 함수 답변이 필요하다고 생각합니다. 그래서 :

>>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.popitem()), d)

용법:

>>> mrep('abcabc', {'a': '1', 'c': '2'})
'1b21b2'

노트:

  • 이것은 입력 사전을 소비합니다.
  • Python dicts는 3.6부터 키 순서를 유지합니다. 다른 답변의 해당 경고는 더 이상 관련이 없습니다. 이전 버전과의 호환성을 위해 튜플 기반 버전을 사용할 수 있습니다.
>>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.pop()), d)
>>> mrep('abcabc', [('a', '1'), ('c', '2')])

참고 : 파이썬의 모든 재귀 함수와 마찬가지로 재귀 깊이가 너무 크면 (즉, 너무 큰 대체 사전) 오류가 발생합니다. 예를 들어 여기를 참조 하십시오 .


큰 사전을 사용할 때 RecursionError가 발생합니다!
Pablo

@Pablo 흥미로운. 얼마나 커? 이것은 모든 재귀 함수에서 발생합니다. 여기 예를 들어, 참조 : stackoverflow.com/questions/3323001/...
mcsoini

대체 내 사전은 지금까지하려면 string.replace을 사용하는 것입니다 ... 100,000 용어에 가까운 지금까지 가장 좋은 방법.
파블로

1
이 경우 @Pablo에서는 재귀 함수를 사용할 수 없습니다. 일반적으로 sys.getrecursionlimit()최대 1000입니다. 루프 또는 이와 유사한 것을 사용하거나 대체를 단순화하십시오.
mcsoini

네, 지름길이 정말 두렵습니다.
Pablo

1

나는 속도에 대해 모른다. 그러나 이것은 나의 임시 빠른 수정이다.

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 정규식 답변이 마음에 듭니다. 참고-하나의 새로운 값이 다른 값의 하위 문자열 인 경우 연산은 정식이 아닙니다.


1

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

여기 에서 예를 찾을 수 있습니다 . 텍스트의 대체는 목록에 표시된 순서대로 수행됩니다.


1

한 문자 만 바꾸려면 translateand를 사용하십시오 str.maketrans.

tl; dr> result_string = your_string.translate(str.maketrans(dict_mapping))


데모

my_string = 'This is a test string.'
dict_mapping = {'i': 's', 's': 'S'}
result_good = my_string.translate(str.maketrans(dict_mapping))
result_bad = my_string
for x, y in dict_mapping.items():
    result_bad = result_bad.replace(x, y)
print(result_good)  # ThsS sS a teSt Strsng.
print(result_bad)   # ThSS SS a teSt StrSng.

0

Andrew의 귀중한 답변에서 시작하여 파일에서 사전을로드하고 열린 폴더의 모든 파일을 대체하여 대체 작업을 수행하는 스크립트를 개발했습니다. 스크립트는 구분 기호를 설정할 수있는 외부 파일에서 매핑을로드합니다. 나는 초보자이지만 여러 파일에서 여러 번 대체 할 때이 스크립트가 매우 유용하다는 것을 알았습니다. 초 단위로 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()

0

이것이 문제에 대한 나의 해결책입니다. 다른 단어를 한 번에 바꾸기 위해 챗봇에서 사용했습니다.

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


0

다른 예 : 입력 목록

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]] 

-2

또는 빠른 해킹의 경우 :

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)

-2

사전을 사용하여 수행하는 또 다른 방법은 다음과 같습니다.

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.