एक स्ट्रिंग में कई पात्रों को बदलने का सबसे अच्छा तरीका है?


199

मैं इस प्रकार कुछ पात्रों को बदलने के लिए की जरूरत है: &\&, #\#, ...

मैं निम्नानुसार कोडित हूं, लेकिन मुझे लगता है कि कुछ बेहतर तरीका होना चाहिए। कोई संकेत?

strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...

जवाबों:


434

दो वर्णों को प्रतिस्थापित करना

मैंने वर्तमान उत्तरों में सभी विधियों को एक अतिरिक्त के साथ समयबद्ध किया।

के इनपुट स्ट्रिंग के साथ abc&def#ghiऔर जगह और -> \ & और # -> \ #, सबसे तेज़ तरीका एक साथ इस तरह प्रतिस्थापन श्रृंखला के लिए गया था: text.replace('&', '\&').replace('#', '\#')

प्रत्येक समारोह के लिए समय:

  • a) 1000000 लूप्स, सर्वश्रेष्ठ 3: 1.47 μs प्रति लूप
  • बी) १०००००० लूप, सर्वश्रेष्ठ ३: १.५१ μ प्रति लूप
  • c) 100000 लूप्स, सर्वश्रेष्ठ 3: 12.3 μs प्रति लूप
  • d) 100000 छोरों, 3: 12 μs प्रति लूप का सबसे अच्छा
  • ई) 100000 लूप्स, सर्वश्रेष्ठ 3: 3.27 μ प्रति लूप
  • च) 1000000 लूप्स, सर्वश्रेष्ठ 3: 0.817 μs प्रति लूप
  • छ) 100000 लूप्स, सर्वश्रेष्ठ 3: 3.64 μs प्रति लूप
  • h) 1000000 लूप्स, सर्वश्रेष्ठ 3: 0.927 μs प्रति लूप
  • i) 1000000 लूप्स, सर्वश्रेष्ठ 3: 0.814 μs प्रति लूप

यहाँ कार्य हैं:

def a(text):
    chars = "&#"
    for c in chars:
        text = text.replace(c, "\\" + c)


def b(text):
    for ch in ['&','#']:
        if ch in text:
            text = text.replace(ch,"\\"+ch)


import re
def c(text):
    rx = re.compile('([&#])')
    text = rx.sub(r'\\\1', text)


RX = re.compile('([&#])')
def d(text):
    text = RX.sub(r'\\\1', text)


def mk_esc(esc_chars):
    return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
esc = mk_esc('&#')
def e(text):
    esc(text)


def f(text):
    text = text.replace('&', '\&').replace('#', '\#')


def g(text):
    replacements = {"&": "\&", "#": "\#"}
    text = "".join([replacements.get(c, c) for c in text])


def h(text):
    text = text.replace('&', r'\&')
    text = text.replace('#', r'\#')


def i(text):
    text = text.replace('&', r'\&').replace('#', r'\#')

इस तरह समय पर:

python -mtimeit -s"import time_functions" "time_functions.a('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.b('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.c('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.d('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.e('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.f('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.g('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.h('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.i('abc&def#ghi')"

17 अक्षरों की जगह

यहां समान कोड समान है लेकिन अधिक वर्णों के साथ बचने के लिए (\ _ * _ {}> # + -! $):।

def a(text):
    chars = "\\`*_{}[]()>#+-.!$"
    for c in chars:
        text = text.replace(c, "\\" + c)


def b(text):
    for ch in ['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:
        if ch in text:
            text = text.replace(ch,"\\"+ch)


import re
def c(text):
    rx = re.compile('([&#])')
    text = rx.sub(r'\\\1', text)


RX = re.compile('([\\`*_{}[]()>#+-.!$])')
def d(text):
    text = RX.sub(r'\\\1', text)


def mk_esc(esc_chars):
    return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
esc = mk_esc('\\`*_{}[]()>#+-.!$')
def e(text):
    esc(text)


def f(text):
    text = text.replace('\\', '\\\\').replace('`', '\`').replace('*', '\*').replace('_', '\_').replace('{', '\{').replace('}', '\}').replace('[', '\[').replace(']', '\]').replace('(', '\(').replace(')', '\)').replace('>', '\>').replace('#', '\#').replace('+', '\+').replace('-', '\-').replace('.', '\.').replace('!', '\!').replace('$', '\$')


def g(text):
    replacements = {
        "\\": "\\\\",
        "`": "\`",
        "*": "\*",
        "_": "\_",
        "{": "\{",
        "}": "\}",
        "[": "\[",
        "]": "\]",
        "(": "\(",
        ")": "\)",
        ">": "\>",
        "#": "\#",
        "+": "\+",
        "-": "\-",
        ".": "\.",
        "!": "\!",
        "$": "\$",
    }
    text = "".join([replacements.get(c, c) for c in text])


def h(text):
    text = text.replace('\\', r'\\')
    text = text.replace('`', r'\`')
    text = text.replace('*', r'\*')
    text = text.replace('_', r'\_')
    text = text.replace('{', r'\{')
    text = text.replace('}', r'\}')
    text = text.replace('[', r'\[')
    text = text.replace(']', r'\]')
    text = text.replace('(', r'\(')
    text = text.replace(')', r'\)')
    text = text.replace('>', r'\>')
    text = text.replace('#', r'\#')
    text = text.replace('+', r'\+')
    text = text.replace('-', r'\-')
    text = text.replace('.', r'\.')
    text = text.replace('!', r'\!')
    text = text.replace('$', r'\$')


def i(text):
    text = text.replace('\\', r'\\').replace('`', r'\`').replace('*', r'\*').replace('_', r'\_').replace('{', r'\{').replace('}', r'\}').replace('[', r'\[').replace(']', r'\]').replace('(', r'\(').replace(')', r'\)').replace('>', r'\>').replace('#', r'\#').replace('+', r'\+').replace('-', r'\-').replace('.', r'\.').replace('!', r'\!').replace('$', r'\$')

यहां एक ही इनपुट स्ट्रिंग के परिणाम दिए गए हैं abc&def#ghi:

  • a) 100000 लूप्स, सर्वश्रेष्ठ 3: 6.72 μs प्रति लूप
  • बी) १००००० लूप्स, सर्वश्रेष्ठ ३: २.६४ loop प्रति लूप
  • c) 100000 लूप्स, सर्वश्रेष्ठ 3: 11.9 μs प्रति लूप
  • डी) 100000 छोरों, 3 का सबसे अच्छा: 4.92 μs प्रति लूप
  • ई) 100000 लूप्स, सर्वश्रेष्ठ 3: 2.96 μs प्रति लूप
  • च) १००००० लूप, सर्वश्रेष्ठ ३: ४.२ ९ per प्रति लूप
  • छ) 100000 लूप्स, सर्वश्रेष्ठ 3: 4.68 μs प्रति लूप
  • एच) १००००० लूप्स, सर्वश्रेष्ठ ३: ४.s३ per प्रति लूप
  • i) 100000 लूप्स, सर्वश्रेष्ठ 3: 4.24 μs प्रति लूप

और एक लंबी इनपुट स्ट्रिंग के साथ ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$):

  • a) 100000 लूप्स, सर्वश्रेष्ठ 3: 7.59 μs प्रति लूप
  • बी) १००००० लूप्स, सर्वश्रेष्ठ ३: ६.५४ μs प्रति लूप
  • c) 100000 लूप्स, सर्वश्रेष्ठ 3: 16.9 μs प्रति लूप
  • d) 100000 लूप्स, सर्वश्रेष्ठ 3: 7.29 μs प्रति लूप
  • ई) 100000 लूप्स, सर्वश्रेष्ठ 3: 12.2 μs प्रति लूप
  • च) 100000 लूप, 3: 5.38 μs प्रति लूप का सबसे अच्छा
  • छ) 10000 लूप, 3 का सर्वश्रेष्ठ: 21.7 μs प्रति लूप
  • ज) १००००० लूप, सर्वश्रेष्ठ ३: ५. per μ प्रति लूप
  • i) 100000 लूप्स, सर्वश्रेष्ठ 3: 5.13 μs प्रति लूप

कुछ प्रकारों को जोड़ना:

def ab(text):
    for ch in ['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:
        text = text.replace(ch,"\\"+ch)


def ba(text):
    chars = "\\`*_{}[]()>#+-.!$"
    for c in chars:
        if c in text:
            text = text.replace(c, "\\" + c)

छोटे इनपुट के साथ:

  • ab) 100000 लूप्स, सर्वश्रेष्ठ 3: 7.05 μs प्रति लूप
  • बा) १००००० लूप्स, सर्वश्रेष्ठ ३: २.४ μs प्रति लूप

लंबे इनपुट के साथ:

  • ab) 100000 लूप, 3: 7.71 μs प्रति लूप का सर्वश्रेष्ठ
  • बा) १००००० लूप, सर्वश्रेष्ठ ३: ६.०s μs प्रति लूप

इसलिए मैं baपठनीयता और गति के लिए उपयोग करने जा रहा हूं ।

परिशिष्ट

टिप्पणी में haccks से प्रेरित होकर, के बीच एक अंतर abऔर baहै if c in text:जांच। आइए उन्हें दो और वेरिएंट के खिलाफ टेस्ट करते हैं:

def ab_with_check(text):
    for ch in ['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:
        if ch in text:
            text = text.replace(ch,"\\"+ch)

def ba_without_check(text):
    chars = "\\`*_{}[]()>#+-.!$"
    for c in chars:
        text = text.replace(c, "\\" + c)

Python 2.7.14 और 3.6.3, और पहले सेट से एक अलग मशीन पर μs प्रति लूप में टाइम्स, इसलिए सीधे तुलना नहीं की जा सकती।

╭────────────╥──────┬───────────────┬──────┬──────────────────╮
 Py, input    ab   ab_with_check   ba   ba_without_check 
╞════════════╬══════╪═══════════════╪══════╪══════════════════╡
 Py2, short  8.81     4.22        3.45     8.01          
 Py3, short  5.54     1.34        1.46     5.34          
├────────────╫──────┼───────────────┼──────┼──────────────────┤
 Py2, long   9.3      7.15        6.85     8.55          
 Py3, long   7.43     4.38        4.41     7.02          
└────────────╨──────┴───────────────┴──────┴──────────────────┘

हम यह निष्कर्ष निकाल सकते हैं कि:

  • चेक वाले लोग बिना चेक के 4x तक तेज होते हैं

  • ab_with_checkपाइथन 3 पर लीड में थोड़ा है, लेकिन ba(चेक के साथ) पायथन 2 पर अधिक लीड है

  • हालाँकि, यहां सबसे बड़ा सबक पायथन 3 है जो पायथन 2 की तुलना में 3x तेज है ! पायथन 3 पर सबसे धीमी और पायथन 2 पर सबसे तेज़ के बीच बहुत बड़ा अंतर नहीं है!


4
यह अपवादित उत्तर क्यों नहीं है?
चिकन सूप

में if c in text:आवश्यक है ba?
haccks

@ झटके यह आवश्यक नहीं है, लेकिन इसके साथ 2-3x तेज है। लघु स्ट्रिंग, के साथ: 1.45 usec per loopऔर बिना:, 5.3 usec per loopलंबी स्ट्रिंग, साथ: 4.38 usec per loopऔर बिना 7.03 usec per loop:। (ध्यान दें कि ये सीधे ऊपर के परिणामों के साथ तुलनीय नहीं हैं, क्योंकि यह एक अलग मशीन आदि है)
ह्यूगो

1
@Hugo; मुझे लगता है कि समय में इस अंतर की वजह से है replaceकेवल कहा जाता है जब cमें पाया जाता है textके मामले में ba, जबकि यह में हर चरण में कहा जाता है ab
हॉक

2
@ धन्यवाद, मैंने अपने उत्तर को और समय के साथ अपडेट किया है: चेक जोड़ना दोनों के लिए बेहतर है, लेकिन सबसे बड़ा सबक पायथन 3 तेजी से 3x तक है!
ह्यूगो

73
>>> string="abc&def#ghi"
>>> for ch in ['&','#']:
...   if ch in string:
...      string=string.replace(ch,"\\"+ch)
...
>>> print string
abc\&def\#ghi

डबल बैकस्लैश की आवश्यकता क्यों थी? सिर्फ "\" काम क्यों नहीं करता है?
एक्सोलोटल

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

आपको करने की आवश्यकता क्यों है string=string.replace(ch,"\\"+ch)? बस string.replace(ch,"\\"+ch)इतना ही काफी नहीं है?
1

1
@MattSom प्रतिस्थापित () मूल स्ट्रिंग को संशोधित नहीं करता है, लेकिन एक प्रति लौटाता है। तो आपको कोड के लिए किसी भी प्रभाव के लिए असाइनमेंट की आवश्यकता है।
बेन ब्रायन

3
क्या तुम सच में अगर की जरूरत है? ऐसा लगता है कि रिप्लेसमेंट वैसे भी क्या कर रहा होगा।
लोरेंजो

32

बस replaceइस तरह से कार्य श्रृंखला

strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi

यदि प्रतिस्थापन संख्या में अधिक होने जा रहे हैं, तो आप इसे इस सामान्य तरीके से कर सकते हैं

strs, replacements = "abc&def#ghi", {"&": "\&", "#": "\#"}
print "".join([replacements.get(c, c) for c in strs])
# abc\&def\#ghi

30

यहाँ एक python3 विधि का उपयोग किया जाता है str.translateऔर str.maketrans:

s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))

मुद्रित स्ट्रिंग है abc\&def\#ghi


2
यह एक अच्छा उत्तर है, लेकिन व्यवहार में एक .translate()तीन जंजीरों की तुलना में धीमा प्रतीत होता है .replace()(CPython 3.6.4 का उपयोग करके)।
चांगको

@Changaco समय के लिए धन्यवाद यह hang व्यवहार में मैं replace()खुद का उपयोग करेगा , लेकिन मैंने पूर्णता की खातिर इस उत्तर को जोड़ा।
tommy.carstensen

बड़े तार और कई प्रतिस्थापनों के लिए यह तेज होना चाहिए, हालांकि कुछ परीक्षण अच्छा होगा ...
ग्रिफ़ेर

ठीक है, यह मेरी मशीन पर नहीं है (2 और 17 प्रतिस्थापन के लिए समान)।
ग्रिफ़ेर

कैसे '\#'वैध है? यह होना चाहिए r'\#'या नहीं '\\#'? शायद एक कोड ब्लॉक प्रारूपण मुद्दा हो सकता है।
समांतर ३

16

क्या आप हमेशा एक बैकस्लैश प्रस्तुत करने जा रहे हैं? यदि ऐसा है, तो प्रयास करें

import re
rx = re.compile('([&#])')
#                  ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)

यह सबसे कुशल तरीका नहीं हो सकता है, लेकिन मुझे लगता है कि यह सबसे आसान है।


15
aarrgghh कोशिशr'\\\1'
जॉन मैकिन

10

पार्टी के लिए देर से, लेकिन मैंने इस मुद्दे के साथ बहुत समय खो दिया जब तक मुझे अपना जवाब नहीं मिला।

लघु और मधुर, translateसे श्रेष्ठ हैreplace । यदि आप समय अनुकूलन के बारे में अधिक रुचि रखते हैं, तो उपयोग न करें replace

यह भी उपयोग करें translateकि क्या आप नहीं जानते हैं कि यदि अक्षरों के सेट को प्रतिस्थापित किया जाए तो अक्षरों के सेट को बदलने के लिए उपयोग किया जाता है।

इसका स्पष्ट उदाहरण:

replaceआप का उपयोग "1234".replace("1", "2").replace("2", "3").replace("3", "4")करने से स्निपेट के वापस लौटने की उम्मीद होगी "2344", लेकिन यह वास्तव में वापस आ जाएगा "4444"

ओपी मूल रूप से वांछित होने के लिए अनुवाद करता है।


6

आप जेनेरिक एस्केप फंक्शन लिखने पर विचार कर सकते हैं:

def mk_esc(esc_chars):
    return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])

>>> esc = mk_esc('&#')
>>> print esc('Learn & be #1')
Learn \& be \#1

इस तरह से आप अपने फ़ंक्शन को चरित्र की एक सूची के साथ कॉन्फ़िगर करने योग्य बना सकते हैं जिसे बच जाना चाहिए।


3

FYI करें, यह ओपी के लिए बहुत कम या कोई उपयोग नहीं है, लेकिन अन्य पाठकों के लिए इसका उपयोग हो सकता है (कृपया नीचे न जाएं, मुझे इसकी जानकारी है)।

कुछ हद तक हास्यास्पद लेकिन दिलचस्प अभ्यास के रूप में, मैं यह देखना चाहता था कि क्या मैं कई छंदों को बदलने के लिए पायथन फंक्शनल प्रोग्रामिंग का उपयोग कर सकता हूं। मुझे पूरा यकीन है कि यह सिर्फ कॉलिंग रिप्लेस () को दो बार नहीं हराता है। और अगर प्रदर्शन एक मुद्दा था, तो आप इसे आसानी से जंग, सी, जूलिया, पर्ल, जावा, जावास्क्रिप्ट और शायद यहां तक ​​कि जाग में हरा सकते हैं। यह एक बाहरी ' हेल्पर्स ' पैकेज का उपयोग करता है जिसे पाइटोल्ज़ कहा जाता है , जिसे साइथन ( साइटोलज़, यह एक पाइपर पैकेज ) के माध्यम से त्वरित किया जाता है ।

from cytoolz.functoolz import compose
from cytoolz.itertoolz import chain,sliding_window
from itertools import starmap,imap,ifilter
from operator import itemgetter,contains
text='&hello#hi&yo&'
char_index_iter=compose(partial(imap, itemgetter(0)), partial(ifilter, compose(partial(contains, '#&'), itemgetter(1))), enumerate)
print '\\'.join(imap(text.__getitem__, starmap(slice, sliding_window(2, chain((0,), char_index_iter(text), (len(text),))))))

मैं इसे समझाने भी नहीं जा रहा हूं क्योंकि कोई भी इसका उपयोग कई जगह पूरा करने के लिए परेशान नहीं करेगा। फिर भी, मैंने ऐसा करने में कुछ हद तक निपुण महसूस किया और सोचा कि यह अन्य पाठकों को प्रेरित कर सकता है या एक कोड ऑबफ्यूजेशन प्रतियोगिता जीत सकता है।


1
"कार्यात्मक प्रोग्रामिंग" का अर्थ यह नहीं है "जितना संभव हो उतने कार्यों का उपयोग करना", आप जानते हैं।
क्रेग एंड्रयूज

1
यह पूरी तरह से अच्छा, शुद्ध कार्यात्मक मल्टी-चार प्रतिकृति है : gist.github.com/anonymous/4577424f586173fc6b91a215ea2ce89e कोई आवंटन, कोई म्यूटेशन, कोई साइड इफेक्ट नहीं। पठनीय भी।
क्रेग एंड्रयूज

1

कम करने का उपयोग जो python2.7 और python3 में उपलब्ध है। * आप आसानी से एक साफ और pythonic तरीके से म्यूटेंट सबस्ट्रिंग को बदल सकते हैं।

# Lets define a helper method to make it easy to use
def replacer(text, replacements):
    return reduce(
        lambda text, ptuple: text.replace(ptuple[0], ptuple[1]), 
        replacements, text
    )

if __name__ == '__main__':
    uncleaned_str = "abc&def#ghi"
    cleaned_str = replacer(uncleaned_str, [("&","\&"),("#","\#")])
    print(cleaned_str) # "abc\&def\#ghi"

Python2.7 में आपको कम लेकिन python3 में आयात करने की आवश्यकता नहीं है। * आपको इसे फंक्शनल टूल से आयात करना होगा।



1

इस बारे में कैसा है?

def replace_all(dict, str):
    for key in dict:
        str = str.replace(key, dict[key])
    return str

फिर

print(replace_all({"&":"\&", "#":"\#"}, "&#"))

उत्पादन

\&\#

के समान उत्तर के


0
>>> a = '&#'
>>> print a.replace('&', r'\&')
\&#
>>> print a.replace('#', r'\#')
&\#
>>> 

आप विशेष रूप से बैकस्लैश का इलाज नहीं करने के लिए कच्चे तार के बाद से एक 'रॉ' स्ट्रिंग ('आर' द्वारा प्रतिस्थापित प्रतिस्थापन स्ट्रिंग का उपयोग करके) का उपयोग करना चाहते हैं।


0

रेगेक्स का उपयोग कर उन्नत तरीका

import re
text = "hello ,world!"
replaces = {"hello": "hi", "world":" 2020", "!":"."}
regex = re.sub("|".join(replaces.keys()), lambda match: replaces[match.string[match.start():match.end()]], text)
print(regex)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.