[python] एक स्ट्रिंग में एकाधिक रिक्त स्थान को हटाने का सरल तरीका?



8 Answers

foo आपकी स्ट्रिंग है:

" ".join(foo.split())

चेतावनी दी जानी चाहिए हालांकि यह "सभी सफेद जगहों (अंतरिक्ष, टैब, नई लाइन, वापसी, फॉर्मफीड) हटा देता है"। ( hhsaffar के लिए धन्यवाद, टिप्पणियां देखें) यानी "this is \ta test\n" प्रभावी रूप से समाप्त हो जाएगा "this is a test"

Question

मान लीजिए यह स्ट्रिंग है:

The   fox jumped   over    the log.

इसके परिणामस्वरूप:

The fox jumped over the log.

सबसे सरल, 1-2 लाइनर क्या है जो यह कर सकता है? विभाजन के बिना और सूचियों में जा रहा है ...




string='This is a             string full of spaces          and taps'
string=string.split(' ')
while '' in string:
    string.remove('')
string=' '.join(string)
print(string)

परिणाम :

यह रिक्त स्थान और नल से भरा एक स्ट्रिंग है




import re
string =  re.sub('[ \t\n]+', ' ', 'The     quick brown                \n\n             \t        fox')

यह एकल टैब के साथ सभी टैब, नई लाइनें और एकाधिक सफेद रिक्त स्थान हटा देगा।




"\ S" के साथ regexes का उपयोग करना और सरल string.split () की इच्छा भी अन्य सफेद जगहों को हटाएगी - जैसे न्यूलाइन, कैरिज रिटर्न, टैब। जब तक यह वांछित नहीं है, केवल कई रिक्त स्थान करने के लिए , मैं इन उदाहरणों को प्रस्तुत करता हूं।

संपादित करें: जैसा कि मैं नहीं कर रहा हूं, मैं इस पर सो गया, और अंतिम परिणामों पर एक टाइपो को सुधारने के अलावा (v3.3.3 @ 64-बिट, 32-बिट नहीं), स्पष्ट ने मुझे मारा: परीक्षण स्ट्रिंग अपेक्षाकृत छोटी थी ।

तो, मुझे ... 11 पैराग्राफ, 1000 शब्द, लोरेम इप्सम के 6665 बाइट्स और यथार्थवादी समय परीक्षण प्राप्त करने के लिए मिला। मैंने फिर यादृच्छिक लंबाई अतिरिक्त रिक्त स्थान जोड़े:

original_string = ''.join(word + (' ' * random.randint(1, 10)) for word in lorem_ipsum.split(' '))

मैंने "उचित join " को भी सही किया; यदि कोई परवाह करता है, तो एक-लाइनर अनिवार्य रूप से किसी भी अग्रणी / पीछे की जगहों की एक पट्टी करेगा, यह सही संस्करण एक अग्रणी / पीछे की जगह को सुरक्षित रखता है (लेकिन केवल एक ;-)। (मुझे यह पता चला क्योंकि यादृच्छिक रूप से दूरी वाले lorem_ipsum को अंत में अतिरिक्त रिक्त स्थान मिले और इस प्रकार lorem_ipsum विफल रहा।)

# setup = '''

import re

def while_replace(string):
    while '  ' in string:
        string = string.replace('  ', ' ')

    return string

def re_replace(string):
    return re.sub(r' {2,}' , ' ', string)

def proper_join(string):
    split_string = string.split(' ')

    # To account for leading/trailing spaces that would simply be removed
    beg = ' ' if not split_string[ 0] else ''
    end = ' ' if not split_string[-1] else ''

    # versus simply ' '.join(item for item in string.split(' ') if item)
    return beg + ' '.join(item for item in split_string if item) + end

original_string = """Lorem    ipsum        ... no, really, it kept going...          malesuada enim feugiat.         Integer imperdiet    erat."""

assert while_replace(original_string) == re_replace(original_string) == proper_join(original_string)

#'''
# while_replace_test
new_string = original_string[:]

new_string = while_replace(new_string)

assert new_string != original_string
# re_replace_test
new_string = original_string[:]

new_string = re_replace(new_string)

assert new_string != original_string
# proper_join_test
new_string = original_string[:]

new_string = proper_join(new_string)

assert new_string != original_string

नोट: " while संस्करण" ने मूल_स्ट्रिंग की एक प्रति बनाई, जैसा कि मेरा मानना ​​है कि एक बार पहले रन पर संशोधित किया गया था, लगातार रन तेज होंगे (अगर केवल थोड़ी देर तक)। चूंकि यह समय जोड़ता है, मैंने इस स्ट्रिंग प्रति को दो अन्य में जोड़ा ताकि समय केवल तर्क में अंतर दिखाए। ध्यान रखें कि stmt उदाहरणों पर मुख्य stmt केवल एक बार निष्पादित किया जाएगा ; जिस तरह से मैंने यह किया, वही लूप उसी लेबल पर काम करता था, original_string , इस प्रकार दूसरा रन, ऐसा करने के लिए कुछ भी नहीं होगा। जिस तरह से यह अभी स्थापित है, दो अलग-अलग लेबलों का उपयोग करके फ़ंक्शन को कॉल करना, यह कोई समस्या नहीं है। मैंने सभी श्रमिकों को यह सत्यापित करने के लिए assert वक्तव्य जोड़े assert कि हम प्रत्येक पुनरावृत्ति को बदलते हैं (उन लोगों के लिए जो संदिग्ध हो सकते हैं)। उदाहरण के लिए, इसे बदलें और यह टूट जाता है:

# while_replace_test
new_string = original_string[:]

new_string = while_replace(new_string)

assert new_string != original_string # will break the 2nd iteration

while '  ' in original_string:
    original_string = original_string.replace('  ', ' ')
Tests run on a laptop with an i5 processor running Windows 7 (64-bit).

timeit.Timer(stmt = test, setup = setup).repeat(7, 1000)

test_string = 'The   fox jumped   over\n\t    the log.' # trivial

Python 2.7.3, 32-bit, Windows
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.001066 |   0.001260 |   0.001128 |   0.001092
     re_replace_test |   0.003074 |   0.003941 |   0.003357 |   0.003349
    proper_join_test |   0.002783 |   0.004829 |   0.003554 |   0.003035

Python 2.7.3, 64-bit, Windows
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.001025 |   0.001079 |   0.001052 |   0.001051
     re_replace_test |   0.003213 |   0.004512 |   0.003656 |   0.003504
    proper_join_test |   0.002760 |   0.006361 |   0.004626 |   0.004600

Python 3.2.3, 32-bit, Windows
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.001350 |   0.002302 |   0.001639 |   0.001357
     re_replace_test |   0.006797 |   0.008107 |   0.007319 |   0.007440
    proper_join_test |   0.002863 |   0.003356 |   0.003026 |   0.002975

Python 3.3.3, 64-bit, Windows
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.001444 |   0.001490 |   0.001460 |   0.001459
     re_replace_test |   0.011771 |   0.012598 |   0.012082 |   0.011910
    proper_join_test |   0.003741 |   0.005933 |   0.004341 |   0.004009
test_string = lorem_ipsum
# Thanks to http://www.lipsum.com/
# "Generated 11 paragraphs, 1000 words, 6665 bytes of Lorem Ipsum"

Python 2.7.3, 32-bit
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.342602 |   0.387803 |   0.359319 |   0.356284
     re_replace_test |   0.337571 |   0.359821 |   0.348876 |   0.348006
    proper_join_test |   0.381654 |   0.395349 |   0.388304 |   0.388193    

Python 2.7.3, 64-bit
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.227471 |   0.268340 |   0.240884 |   0.236776
     re_replace_test |   0.301516 |   0.325730 |   0.308626 |   0.307852
    proper_join_test |   0.358766 |   0.383736 |   0.370958 |   0.371866    

Python 3.2.3, 32-bit
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.438480 |   0.463380 |   0.447953 |   0.446646
     re_replace_test |   0.463729 |   0.490947 |   0.472496 |   0.468778
    proper_join_test |   0.397022 |   0.427817 |   0.406612 |   0.402053    

Python 3.3.3, 64-bit
                test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
  while_replace_test |   0.284495 |   0.294025 |   0.288735 |   0.289153
     re_replace_test |   0.501351 |   0.525673 |   0.511347 |   0.508467
    proper_join_test |   0.422011 |   0.448736 |   0.436196 |   0.440318

छोटी स्ट्रिंग के लिए, ऐसा लगता है कि थोड़ी देर के लिए लूप सबसे तेज़ है, उसके बाद पाइथोनिक स्ट्रिंग-स्प्लिट / जॉइन, और पीछे की तरफ खींचने वाला रेगेक्स होता है।

गैर-तुच्छ तारों के लिए , ऐसा लगता है कि विचार करने के लिए थोड़ा और कुछ है। 32-बिट 2.7? बचाव के लिए यह regex है! 2.7 64-बिट? while लूप एक सभ्य मार्जिन से सबसे अच्छा है। 32-बिट 3.2, "उचित" join साथ join । 64-बिट 3.3, while लिए जाओ। फिर।

अंत में, यदि कोई / जहां / आवश्यकता हो तो प्रदर्शन में सुधार हो सकता है , लेकिन मंत्र को याद रखना हमेशा सर्वोत्तम होता है :

  1. इसे काम करने लायक बनाओ
  2. इसको सही करो
  3. इसे तेज़ी से करें

इनाल, वाईएमएमवी, कैविट एम्प्टर!




यह भी काम करता प्रतीत होता है:

while "  " in s:
    s=s.replace("  "," ")

जहां वेरिएबल आपकी स्ट्रिंग का प्रतिनिधित्व करता है।




उपयोगकर्ता द्वारा उत्पन्न तारों के लिए आप सबसे तेज़ हो सकते हैं:

    if '  ' in text:
        while '  ' in text:
            text = text.replace('  ', ' ')

शॉर्ट सर्किटिंग इसे पाइथोनलारी के व्यापक उत्तर से थोड़ा तेज बनाता है। इसके लिए जाएं यदि आप दक्षता के बाद हैं, और सख्ती से एकल अंतरिक्ष विविधता के अतिरिक्त सफेद जगहों को कम करने की तलाश में हैं




अन्य विकल्प

>>> import re
>>> str = 'this is a            string with    multiple spaces and    tabs'
>>> str = re.sub('[ \t]+' , ' ', str)
>>> print str
this is a string with multiple spaces and tabs



पिछले समाधानों के समान, लेकिन अधिक विशिष्ट: दो या दो से अधिक रिक्त स्थान को एक के साथ बदलें:

>>> import re
>>> s = "The   fox jumped   over    the log."
>>> re.sub('\s{2,}', ' ', s)
'The fox jumped over the log.'



कुछ मामलों में यह उस चरित्र के एक उदाहरण के साथ प्रत्येक व्हाइटस्पेस चरित्र की लगातार घटनाओं को प्रतिस्थापित करने के लिए वांछनीय है। आप ऐसा करने के लिए बैकरेफर के साथ एक नियमित अभिव्यक्ति का उपयोग करेंगे।

(\s)\1{1,} किसी भी सफेद स्थान चरित्र से मेल खाता है, उसके बाद उस चरित्र की एक या अधिक घटनाएं होती हैं। अब, आपको बस इतना करना है कि मैच के प्रतिस्थापन के रूप में पहला समूह ( \1 ) निर्दिष्ट करें।

एक समारोह में इसे लपेटना:

import re

def normalize_whitespace(string):
    return re.sub(r'(\s)\1{1,}', r'\1', string)
>>> normalize_whitespace('The   fox jumped   over    the log.')
'The fox jumped over the log.'
>>> normalize_whitespace('First    line\t\t\t \n\n\nSecond    line')
'First line\t \nSecond line'



Related