कैसे एक स्ट्रिंग के कई substrates को बदलने के लिए?


284

मैं कई स्ट्रिंग्स को बदलने के लिए .replace फ़ंक्शन का उपयोग करना चाहूंगा।

मेरे पास वर्तमान में है

string.replace("condition1", "")

लेकिन ऐसा कुछ करना चाहेंगे

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

हालांकि यह अच्छा वाक्यविन्यास की तरह महसूस नहीं करता है

ऐसा करने का उचित तरीका क्या है? किस तरह से grep / regex में आप कर सकते हैं \1और \2फ़ील्ड को कुछ खोज स्ट्रिंग में बदल सकते हैं


7
क्या आपने प्रदान किए गए सभी समाधानों की कोशिश की? कौन सा तेज है?
tommy.carstensen

मैंने अलग-अलग परिदृश्यों में सभी उत्तरों का परीक्षण करने के लिए समय लिया है। देखें stackoverflow.com/questions/59072514/...
पाब्लो

1
ईमानदारी से, मैं अन्य सभी के लिए आपके जंजीर दृष्टिकोण को पसंद करता हूं। मैं एक समाधान की तलाश में यहां उतरा और तुम्हारा इस्तेमाल किया और यह ठीक काम करता है।
frakman1

@ frakman1 +1। कोई सुराग नहीं कि यह अधिक क्यों नहीं उतारा जाता है। अन्य सभी विधियाँ कोड पठन को कठिन बना देती हैं। यदि कोई फ़ंक्शन पास सरणियों को बदलने के लिए है, तो यह काम करेगा। लेकिन आपकी जंजीर विधि सबसे स्पष्ट है (कम से कम प्रतिस्थापन की स्थिर संख्या के साथ)
आइसफायर

जवाबों:


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
प्रतिस्थापन एकल पास में होता है।
एंड्रयू क्लार्क

26
dk विटामिन: यह बहुत चालाक नहीं है, यह उतना चालाक भी नहीं है जितना कि होना चाहिए (हमें "" | ") के साथ जुड़ने से पहले कुंजियों से बचना चाहिए। ऐसा क्यों नहीं है? क्योंकि इस तरह से हम इसे एक पास में क्या (तेज =), और हम एक ही समय में सब प्रतिस्थापन करते हैं, की तरह संघर्ष से परहेज "spamham sha".replace("spam", "eggs").replace("sha","md5")किया जा रहा है "eggmd5m md5"के बजाय"eggsham md5"
भेड़ उड़ान

8
@AndrewClark मैं बहुत सराहना करता हूं अगर आप यह बता सकते हैं कि लैम्बडा के साथ अंतिम पंक्ति पर क्या हो रहा है।
खनिज

11
नमस्ते वहाँ, मैंने इस स्निपेट के एक स्पष्ट संस्करण के साथ एक छोटा सा जिस्ट बनाया। यह थोड़ा और अधिक कुशल होना चाहिए: gist.github.com/bgusach/a967e0587d6e01e889fd1d776c5f3729
bgusach

15
अजगर 3 के लिए, पुनरावृत्तियों () के बजाय आइटम () का उपयोग करें।
जंगरी

127

आप बस एक अच्छा सा लूपिंग फंक्शन बना सकते हैं।

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

जहां textपूरा स्ट्रिंग है और dicएक शब्दकोश है - प्रत्येक परिभाषा एक स्ट्रिंग है जो एक मैच को शब्द में बदल देगी।

नोट : पायथन 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

"यह मेरा कुत्ता है और यह मेरा सुअर है।"

एक आदेश फिक्स का उपयोग करना संभव है।

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
जिस क्रम में आप अलग-अलग प्रतिस्थापन लागू करते हैं वह मायने रखेगा - इसलिए एक मानक तानाशाही का उपयोग करने के बजाय, एक OrderedDict- या 2-ट्यूपल्स की सूची का उपयोग करने पर विचार करें ।
स्लॉथ्रोप

5
यह स्ट्रिंग को दो बार पुनरावृत्त करता है ... प्रदर्शन के लिए अच्छा नहीं है।
वैलेंटाइन लोरेंट्ज़

6
प्रदर्शन-वार यह वैलेन्टिन द्वारा कहे जाने की तुलना में बदतर है - यह पाठ को कई बार पार कर लेगा क्योंकि इसमें कुछ आइटम डिक हैं! ठीक है अगर 'पाठ' छोटा है, लेकिन बड़े पाठ के लिए भयानक है।
जोंडनर

3
यह कुछ मामलों के लिए एक अच्छा समाधान है। उदाहरण के लिए, मैं सिर्फ 2 वर्णों को उप करना चाहता हूं और वे उस आदेश की परवाह नहीं करते हैं जो वे जाते हैं क्योंकि प्रतिस्थापन कुंजी किसी भी मूल्य से मेल नहीं खाती हैं। लेकिन मैं चाहता हूं कि यह स्पष्ट हो कि क्या हो रहा है।
नाथन गारबेडियन

5
ध्यान दें कि यह अप्रत्याशित परिणाम दे सकता है क्योंकि पहले पुनरावृत्ति में नए सम्मिलित पाठ को दूसरे पुनरावृत्ति में मिलान किया जा सकता है। उदाहरण के लिए, यदि हम भोलेपन से सभी 'ए' को 'बी' और सभी 'बी' को 'सी' से बदलने की कोशिश करते हैं, तो स्ट्रिंग 'एबी' को 'सीसी' में बदल दिया जाएगा, न कि 'बीसी' को।
अंबोज़ बिज्जक

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 के लिए ((r '\ s'।, ''), (R (\ 's,', ',')):
मार्टिन

2
इसे बनाने के लिए 1-लाइनर: ss = [s.replace (* r) in r (("भूरा", "लाल"), ("आलसी", "जल्दी"))] [0]
मार्क K

95

यदि आप कार्यशील होना चाहते हैं, तो कम करने का उपयोग करके पहले समाधान का एक प्रकार है। :)

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 में भी अपरिवर्तित काम करेगा।
मार्टीन्यू

अच्छा! यदि आप पुनरावृत्तियों के बजाय python3 आइटम का उपयोग करते हैं (अब dicts सामान में हटा दिया गया है)।
e.arbitrio

2
@ स्मार्टिन्यू: यह सत्य नहीं है कि यह अजगर 3 में अपरिवर्तित है क्योंकि reduceइसे हटा दिया गया है
मानतानीस

5
@normanius: reduceअभी भी मौजूद है, हालांकि इसे पायथन 3 में functoolsमॉड्यूल ( डॉक्स देखें ) का एक हिस्सा बनाया गया था , इसलिए जब मैंने अपरिवर्तित कहा, मेरा मतलब था कि एक ही कोड चलाया जा सकता है - हालांकि यह माना जाता है कि यह आवश्यक होगा कि इसे संपादित reduceकिया गया importहै चूंकि यह अब बिल्ट-इन नहीं है।
मार्टिउ

35

यह एफजे और मिनीक्वार्क के शानदार जवाबों का एक और संक्षिप्त पुनर्कथन है। आपको एक साथ कई स्ट्रिंग स्ट्रिंग प्रतिस्थापन प्राप्त करने की आवश्यकता है, निम्न कार्य है:

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
हालांकि यह एक अच्छा समाधान है, समवर्ती स्ट्रिंग प्रतिस्थापनाएं ठीक वैसा ही परिणाम नहीं देंगी जैसा कि उन्हें क्रमिक रूप से निष्पादित करना (उनका पीछा करना) - हालांकि यह कोई फर्क नहीं पड़ता।
मार्टीन्यू

2
निश्चित रूप से, rep_dict = {"but": "mut", "mutton": "lamb"}स्ट्रिंग आपके कोड के साथ "button"परिणाम देती है "mutton", लेकिन यह बताएगी "lamb"कि क्या प्रतिस्थापन एक दूसरे के बाद जंजीर थे।
मार्टिन डे

2
यह इस कोड की मुख्य विशेषता है, दोष नहीं। जंजीर प्रतिस्थापन के साथ यह दो शब्दों को एक साथ प्रतिस्थापित करने के वांछित व्यवहार को प्राप्त नहीं कर सका और मेरे उदाहरण में पारस्परिक रूप से।
एमएमज

1
यदि आपको इसकी आवश्यकता नहीं है तो यह एक बड़ी विशेषता नहीं लग सकती है। लेकिन यहां हम एक साथ प्रतिस्थापन के बारे में बात कर रहे हैं , तो यह वास्तव में मुख्य विशेषता है। "जंजीर" प्रतिस्थापन के साथ, उदाहरण का आउटपुट होगा Do you prefer cafe? No, I prefer cafe., जो बिल्कुल भी वांछनीय नहीं है।
एमएमज


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é.

ध्यान दें कि चूंकि प्रतिस्थापन केवल एक पास में किया जाता है, "कैफे" "चाय" में बदल जाता है, लेकिन यह "कैफे" में वापस नहीं बदलता है।

यदि आपको कई बार एक ही प्रतिस्थापन करने की आवश्यकता है, तो आप आसानी से एक प्रतिस्थापन कार्य बना सकते हैं:

>>> 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
क्या कोई मेरे जैसे अजगर नोब्स के लिए इस कदम को समझा सकता है?
जूलियन सुआरेज़

फेलो पायथन नोब यहाँ, तो मैं इसे समझने में एक अधूरा शॉट लेने वाला हूं .. ए। सामान-से-जगह (कुंजी "|") में शामिल होने और तर्क (यदि मैच एक कुंजी है, तो वापसी मूल्य) में key_values ​​को तोड़ें बी। रेगेक्स पार्सर ("पैटर्न" बनाएं जो कुंजियों की तलाश में है, और दिए गए तर्क का उपयोग करता है) - इसे लंबोदा फ़ंक्शन में लपेटें और वापस लौटें। सामान मैं अब देख रहा हूँ: re.M, और प्रतिस्थापन तर्क के लिए लैम्ब्डा की आवश्यकता।
फॉक्स

1
@ फॉक्स आपको मिल गया। आप एक मेमने का उपयोग करने के बजाय एक फ़ंक्शन को परिभाषित कर सकते हैं, यह कोड को छोटा करने के लिए है। लेकिन ध्यान दें कि pattern.subकेवल एक पैरामीटर (बदलने के लिए पाठ) के साथ एक फ़ंक्शन की उम्मीद है, इसलिए फ़ंक्शन को एक्सेस करने की आवश्यकता है replace_dictमल्टीलाइनre.M प्रतिस्थापन की अनुमति देता है (यह डॉक्स में अच्छी तरह से समझाया गया है: docs.python.org/2/library/re.html#re.M )।
मिनीक्वार्क

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तो एक अपवाद को बढ़ाता है, इसलिए उपयोगकर्ताओं से टेम्पलेट प्राप्त करते समय सावधान रहें।
बार्ट फ्राइडेरिच

2
इस दृष्टिकोण का एक दोष यह है कि टेम्पलेट में सभी होने चाहिए, और सभी से अधिक नहीं, $ स्ट्रिंग्स को प्रतिस्थापित किया जाना चाहिए, यहां
रॉल्फबेली

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
यह तब तक काम करता है जब तक आपके पास प्रतिस्थापन क्लैश नहीं होता है। यदि आप के iसाथ प्रतिस्थापित sएक अजीब व्यवहार मिलेगा।
bgusach

1
यदि आदेश महत्वपूर्ण है, तो ऊपर दिए गए निर्देशों के बजाय आप एक सरणी का उपयोग कर सकते हैं: b = [ ['i', 'Z'], ['s', 'Y'] ]; for x,y in (b): a = a.replace(x, y) फिर यदि आप अपने सरणी जोड़े को ऑर्डर करने के लिए सावधान हैं तो आप यह सुनिश्चित कर सकते हैं कि आप पुनरावर्ती रूप से प्रतिस्थापित नहीं करें ()।
CODE-REaD

ऐसा लगता है कि डाइक अब पायथन 3.7.0 से ऑर्डर बनाए रखते हैं । मैंने इसका परीक्षण किया और यह मेरी मशीन पर नवीनतम स्थिर पायथन 3 के साथ काम करता है।
जेम्स कोस

15

शुरू करना Python 3.8, और असाइनमेंट एक्सप्रेशन (पीईपी 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 नहीं है।
पाब्लो

मुझे सूची में आउटपुट क्यों मिलता है?
जॉहनराव 07

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चर का उपयोग कर सकते हैं जिसमें संशोधित पाठ शामिल है।
ज़ेवियर गुहोट

1
यदि आप textएक-लाइनर के नए संस्करण को वापस करना चाहते हैं, तो आप उपयोग [text := text.replace(a, b) for a, b in replacements][-1](नोट [-1]) भी कर सकते हैं , जो सूची समझ के अंतिम तत्व को निकालता है; का अंतिम संस्करण text
ज़ेवियर गुहोट

13

यहाँ मेरा $ 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)

यह इस में है यह सार है, यह संशोधित करने के लिए अगर आप किसी भी प्रस्ताव है संकोच न करें।


1
इसके बजाय इसका स्वीकृत उत्तर होना चाहिए था क्योंकि लंबाई के अवरोही क्रम में छँटाई करके और उनके साथ जुड़कर सभी कुंजियों से regex का निर्माण किया जाता है। रेगेक्स अल्टरनेशन ऑपरेटर। और छंटाई आवश्यक है ताकि किसी भी विकल्प होने पर सभी संभावित विकल्पों में से सबसे लंबे समय तक चुना जाए।
सचिन एस

मैं मानता हूं कि यह सबसे अच्छा समाधान है, छँटाई के लिए धन्यवाद। छंटाई के अलावा मेरे मूल उत्तर के समान है, इसलिए मैंने अपने समाधान के लिए भी छंटनी उधार ली है, यह सुनिश्चित करने के लिए कि कोई भी इस तरह की महत्वपूर्ण विशेषता को याद नहीं करेगा।
mmj

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"

निम्नलिखित फ़ंक्शन आपके शब्दकोश कुंजियों के बीच गलत नियमित अभिव्यक्ति खोजने में मदद कर सकता है (क्योंकि कई से त्रुटि संदेश बहुत अच्छा नहीं है):

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(मेरे प्रयोग की स्थितियों में) की तुलना में लगभग चार गुना धीमी होती है ।

आपको पूरी तरह से फ्लैशटेक्स्ट लाइब्रेरी ( यहाँ पर ब्लॉग पोस्ट , जीथब यहाँ ) का उपयोग करने की कोशिश करनी चाहिए । मेरे मामले में यह प्रत्येक दस्तावेज के लिए 1.8 एस से 0.015 सेकेंड (नियमित भाव 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 से बचने के लिए -> b और b -> c का अनुवाद 'a' में 'c')। Flashtext भी पूरे शब्द के लिए लग रहा है (ताकि से मेल नहीं खाएगी 'वें' है ' है ')। यह ठीक काम करता है यदि आपका लक्ष्य कई शब्द हैं ('हैलो' द्वारा 'यह है' की जगह)।


यदि आपको HTML टैग बदलने की आवश्यकता है तो यह कैसे काम करता है? उदाहरण के लिए बदलने के <p>साथ /n। मैंने आपके दृष्टिकोण की कोशिश की, लेकिन टैग्स के साथ, यह पार्स नहीं लगता है?
अलिसा ५१

1
मुझे यकीन नहीं है कि यह आपकी अपेक्षा के अनुरूप काम नहीं कर रहा है। एक संभावना यह है कि ये टैग रिक्त स्थान से अलग नहीं होते हैं, और याद रखें कि Flashtext पूरे शब्दों के लिए दिखता है। इसका एक तरीका यह है कि पहले एक साधारण प्रतिस्थापन का उपयोग किया जाए, ताकि "हाय <p> वहां" "हाय <p>" बन जाए। जब आप कर रहे हैं (सरल प्रतिस्थापन भी?) अवांछित स्थानों को हटाने के लिए आपको सावधान रहने की आवश्यकता होगी। उम्मीद है की वो मदद करदे।
पाब्लो

धन्यवाद, क्या आप सेट कर सकते हैं <और >एक शब्द के अंत को चिह्नित कर सकते हैं (लेकिन प्रतिस्थापित में शामिल किया जा सकता है)?
अलिसा ५१

1
मेरा मानना ​​है कि "शब्द" केवल रिक्त स्थान द्वारा चिह्नित हैं। शायद कुछ वैकल्पिक पैरामीटर हैं जिन्हें आप "KeywordProcessor" में सेट कर सकते हैं। अन्यथा ऊपर दिए गए दृष्टिकोण पर विचार करें: "<" द्वारा "<" को प्रतिस्थापित करें, फ़्लैशटेक्स्ट को फिर से लागू करें (उदाहरण के लिए, उदाहरण के लिए, "<" से "<" और "\ 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'

टिप्पणियाँ:

  • यह इनपुट शब्दकोश की खपत करता है।
  • अजगर डाइक 3.6 के रूप में महत्वपूर्ण आदेश को संरक्षित करता है; अन्य उत्तरों में संबंधित कैविएट अब प्रासंगिक नहीं हैं। पश्चगामी अनुकूलता के लिए कोई टपल-आधारित संस्करण का सहारा ले सकता है:
>>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.pop()), d)
>>> mrep('abcabc', [('a', '1'), ('c', '2')])

नोट: अजगर में सभी पुनरावर्ती कार्यों के साथ, बहुत बड़ी पुनरावृत्ति गहराई (यानी बहुत बड़े प्रतिस्थापन शब्दकोशों) के परिणामस्वरूप त्रुटि होगी। जैसे देखें यहाँ


मैं एक बड़े शब्दकोश का उपयोग करते समय RecursionError में चलता हूं!
पाब्लो

@ पाब्लो दिलचस्प। कितना बड़ा? ध्यान दें कि यह सभी पुनरावर्ती कार्यों के लिए होता है। उदाहरण के लिए यहाँ देखें: stackoverflow.com/questions/3323001/…
mcsoini

खिलाड़ी को बदलने की मेरी शब्दकोश ... 100k शर्तों के करीब है अब तक string.replace उपयोग कर रहा है अब तक का सबसे अच्छा तरीका।
पाब्लो

1
उस मामले में @ पाब्लो आप पुनरावर्ती कार्यों का उपयोग नहीं कर सकते। सामान्य तौर पर, sys.getrecursionlimit()एक युगल 1000, अधिकतम है। लूप का उपयोग करें या ऐसा कुछ, या प्रतिस्थापन को सरल बनाने का प्रयास करें।
mcsoini

हाँ, मुझे डर है कि यहाँ वास्तव में कोई शॉर्टकट नहीं है।
पाब्लो

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

केवल एक वर्ण को बदलने के लिए, translateऔर str.maketransमेरा पसंदीदा तरीका है।

tl; डॉ।> 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

एंड्रयू के कीमती उत्तर से शुरू करके मैंने एक स्क्रिप्ट विकसित की जो एक फाइल से डिक्शनरी लोड करती है और रिप्लेसमेंट करने के लिए खोले गए फोल्डर की सभी फाइलों को विस्तृत करती है। स्क्रिप्ट बाहरी फ़ाइल से मैपिंग को लोड करती है जिसमें आप विभाजक सेट कर सकते हैं। मैं एक शुरुआत कर रहा हूँ, लेकिन मैं इस स्क्रिप्ट बहुत उपयोगी पाया जब कई फ़ाइलों में कई प्रतिस्थापन कर रहा है। इसने सेकंड में 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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.