문자열에서 여러 공백을 제거하는 간단한 방법이 있습니까?


390

이 문자열을 가정하십시오.

The   fox jumped   over    the log.

로 전환 :

The fox jumped over the log.

이것을 나누고 목록으로 만들지 않고 이것을 달성하는 가장 간단한 (1-2 줄)은 무엇입니까?


22
목록에 대한 혐오감은 무엇입니까? 그것들은 언어의 필수 부분이며, "".join (list_of_words)는 문자열 목록을 공백으로 구분 된 단일 문자열로 만드는 핵심 관용구 중 하나입니다.
PaulMcG

3
@ Tom / @ Paul : 간단한 문자열의 경우 (문자열) 조인은 간단하고 달콤합니다. 그러나 방해하고 싶지 않은 다른 공백이 있으면 더 복잡해집니다.이 경우 "while"또는 정규식 솔루션이 가장 좋습니다. 나는 "올바른"문자열 조인 아래에 이것을 세 가지 방법으로 시간 테스트 결과와 함께 게시했습니다.
pythonlarry

답변:


529
>>> import re
>>> re.sub(' +', ' ', 'The     quick brown    fox')
'The quick brown fox'

20
이 솔루션은 단일 공백 ​​문자 만 처리합니다. nsr81의 솔루션에서와 같이 \ s가 처리하는 탭이나 다른 공백 문자는 대체하지 않습니다.
Taylor Leese

2
사실, string.split모든 종류의 공백도 처리합니다.
Josh Lee

6
공백 문자에만 초점을 맞추고 '\ n 's와 같은 문자에는 영향을 미치지 않기 때문에이 방법을 선호합니다.
hhsaffar

2
네, 그러죠. 그러나 그 strip () 전에해야합니다. 양쪽 끝에서 공백을 제거합니다.
Hardik Patel

17
단일 공간이 단일 공간으로 중복 대체re.sub(' {2,}', ' ', 'The quick brown fox') 되는 것을 방지 하는 데 사용할 수 있습니다 .
AneesAhmed777

541

foo 당신의 문자열입니다 :

" ".join(foo.split())

이렇게하면 "모든 공백 문자 (공백, 탭, 줄 바꿈, 리턴, 용지 공급 )"가 제거됩니다 ( hhsaffar 덕분에 주석 참조). 즉, "this is \t a test\n"로 효과적으로 끝날 것 "this is a test"입니다.


19
"분할 및 목록으로 이동하지 않고 ..."
Gumbo

72
나는 그것이 가장 좋은 대답이라고 생각하기 때문에 "분할과 목록으로 들어 가지 않고 ..."를 무시했습니다.
Taylor Leese

1
이것은 후행 공백을 제거합니다. 텍스트를 유지하려면 text [0 : 1] + "".join (text [1 : -1] .split ()) + text [-1]
user984003

re.sub () 솔루션보다 6 배 빠릅니다.
nerdfever.com

1
@ AstraUvarova-Saturn'sstar 나는 그것을 프로파일했다.
nerdfever.com

85
import re
s = "The   fox jumped   over    the log."
re.sub("\s\s+" , " ", s)

또는

re.sub("\s\s+", " ", s)

쉼표 전에 공간은로 표시되어 있기 때문에 애완 동물 초조PEP 8 로, 사용자가 언급 한 마틴 토마스 코멘트에.


2
나는 r"\s\s+"이미 단일 공간을 대체하지 않도록 정규 표현식을 변경하는 경향이 있습니다 .
Ben Blank

19
해당 동작을 원한다면 "\s{2,}"중간 정도의 정규식 동작을 모르는 해결 방법이 아닌 이유 는 무엇입니까?
Chris Lutz가

2
sub ()는 입력 문자열을 변경하지 않지만 s새 값을 반환합니다.
gcb

1
@moose — 성능보다 가독성 최적화입니다. " 개 이상의 공백을 공백으로 바꾸기"보다는 \s+행이 " 하나 이상의 공백을 공백으로 바꾸기"라고 읽습니다 . 전자는 즉시 멈추고 "한 공간을 한 공간으로 대체하는 이유는 무엇입니까?" 나에게 그것은 (매우 작은) 코드 냄새입니다. 사실은 어쨌든 새로운 문자열로 복사 할 것 같은, 둘 사이에 전혀 성능의 차이가있을 수 기대하지 않을 것이다,에 관계없이 공간이 복사되는 위치의 정지 및 테스트가 에서 .
Ben Blank

8
\s\s+이것은 TAB 문자를 다시 일반 공간으로 정규화하지 않기 때문에 권장 하지 않습니다. SPACE + TAB은 이런 식으로 대체됩니다.
vdboor

51

"\ s"와 함께 정규 표현식을 사용하고 간단한 string.split ()을 사용하면 줄 바꿈, 캐리지 리턴, 탭과 같은 다른 공백 제거 됩니다 . 이것이 바람직하지 않으면, 여러 공간 수행 하기 위해이 예제를 제시합니다.

나는 11 개의 문단, 1000 단어, 6665 바이트의 Lorem Ipsum 을 사용하여 현실적인 시간 테스트를 받고 임의 길이의 여분의 공백을 사용했습니다.

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

원 라이너는 본질적으로 모든 선행 / 트레일 공간을 제거하며 선행 / 트레일 공간을 유지합니다 (단 하나의 ;-).

# 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버전"은 original_string첫 번째 실행에서 일단 수정되면 연속 실행이 더 빠를 것이라고 생각합니다. 시간이 추가됨에 따라이 문자열 복사본을 다른 두 개에 추가하여 시간에 논리의 차이 만 표시했습니다. main stmton timeit인스턴스는 한 번만 실행됩니다 . 내가 원래했던 방식으로 while루프는 동일한 레이블에서 작동 original_string하므로 두 번째 실행에서는 할 일이 없습니다. 두 가지 레이블을 사용하여 함수를 호출하여 지금 설정하는 방식은 문제가되지 않습니다. 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

사소한 문자열의 경우 while 루프가 가장 빠르고 파이썬 문자열 스플릿 / 조인이 있고 정규 표현식이 뒤쪽을 당기는 것처럼 보입니다.

사소한 문자열 의 경우 고려해야 할 것이 더 있습니다. 32 비트 2.7? 구조에 대한 정규식입니다! 2.7 64 비트? while루프는 상당한 차이로, 최고입니다. 32 비트 3.2는 "proper"와 함께 사용하십시오 join. 64 비트 3.3, while루프 로 이동하십시오 . 다시.

결국, 필요한 경우 / 위치 / 필요한 경우 성능을 향상시킬 수 있지만 항상 진언기억하는 것이 가장 좋습니다 .

  1. 작동하게 만들다
  2. 잘되도록하세요
  3. 빨리 해

IANAL, YMMV, Caveat Emptor!


1
' '.join(the_string.split())이것이 일반적인 유스 케이스이므로 단순 을 테스트 한 경우 선호 했지만 작업에 감사드립니다.
wedi

@ wedi : 다른 의견에 따르면 ( Gumbo ; user984003 과 같이 솔루션은 추정 적이며 "모든 경우에"작동하지는 않지만) 이러한 종류의 솔루션은 질문자의 요청을 준수하지 않습니다. .split ( '') 및 comp / gen을 사용할 수 있지만 리드 / 트레일 공간을 다루기 위해 더 많은 것을 얻습니다.
pythonlarry

@wedi : 예 : ' '.join(p for p in s.split(' ') if p)<-여전히 리드 / 트레일 공간을 잃었지만 여러 공간을 차지했습니다. 그들을 유지하려면처럼해야합니다 parts = s.split(' '); (' ' if not parts[0] else '') + ' '.join(p for p in s.split(' ') if p) + (' ' if not parts[-1] else '')!
pythonlarry

진언에 대한 @pythonlarry 감사합니다! 자세한 테스트를 좋아합니다! 6 년이 지난 지금 당신의 생각이나 견해가 바뀌 었는지 궁금합니다.
JayRizzo

발전기를 사용하는 버전 누락
Lee

42

Paul McGuire의 의견에 동의해야합니다. 나에게,

' '.join(the_string.split())

정규식을 꺼내는 것보다 훨씬 좋습니다.

내 측정 (Linux 및 Python 2.5)은 split-then-join이 "re.sub (...)"를 수행하는 것보다 거의 5 배 빠르며 정규 표현식을 한 번 사전 컴파일하고 작업을 수행하면 여전히 3 배 빠름을 보여줍니다 여러 번. 그리고 그것은 훨씬 더 이해하기 쉽습니다- 훨씬 더 파이썬적인 것입니다.


이것은 후행 공백을 제거합니다. 텍스트를 유지하려면 text [0 : 1] + "".join (text [1 : -1] .split ()) + text [-1]
user984003

4
간단한 정규 표현식을 읽는 것이 훨씬 좋습니다. 수행하기 전에 성능을 최적화하지 마십시오.
gcb

@gcb : 왜 안되죠? 높은 처리량 시나리오 (예 : 높은 수요로 인해)가 예상되는 경우 어떻게합니까? 해당 시나리오에서 리소스를 덜 사용하는 것으로 예상되는 것을 배포 해보십시오.
Hassan Baig

1
@HassanBaig 이미 성능 요구 사항이 있다면 실제로 조기 최적화되지 않습니까? 내 요점은 아직 성능에 집착 할 필요가없는 경우에 대한 것입니다. 항상 가독성을 목표로하는 것이 좋습니다.
gcb

14

이전 솔루션과 유사하지만보다 구체적 : 두 개 이상의 공백을 하나로 바꿉니다.

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

11

간단한 영혼

>>> import re
>>> s="The   fox jumped   over    the log."
>>> print re.sub('\s+',' ', s)
The fox jumped over the log.

6

.apply (..)를 사용할 필요없이 Pandas DataFrame에서 문자열 분할 기술을 사용할 수도 있습니다. 이는 많은 문자열에서 작업을 빠르게 수행해야하는 경우에 유용합니다. 여기 한 줄에 있습니다.

df['message'] = (df['message'].str.split()).str.join(' ')

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

이렇게하면 모든 탭, 줄 바꿈 및 단일 공백이있는 여러 공백이 제거됩니다.


그러나 '\ x00'에서 '\ x0020'과 같이 범위에없는 공백 (인쇄 할 수없는) 문자가있는 경우 코드에서 문자를 제거하지 않습니다.
Muskovets

5

나는 다음 방법을 시도했으며 심지어 극단적 인 경우에도 작동합니다.

str1='          I   live    on    earth           '

' '.join(str1.split())

그러나 정규식을 선호하는 경우 다음과 같이 수행 할 수 있습니다.

re.sub('\s+', ' ', str1)

후행 및 종료 공간을 제거하려면 일부 전처리를 수행해야합니다.


3

이것은 또한 작동하는 것 같습니다 :

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

변수가 s문자열을 나타내는 곳 .


2

경우에 따라 모든 공백 문자의 연속 발생을 단일 인스턴스로 바꾸는 것이 바람직 합니다. 문자 . 역 참조가있는 정규식을 사용하면됩니다.

(\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'

2

다른 대안 :

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

2

한 줄의 코드로 문장 앞, 뒤 및 문장 내의 모든 추가 공백을 제거합니다.

sentence = "  The   fox jumped   over    the log.  "
sentence = ' '.join(filter(None,sentence.split(' ')))

설명:

  1. 전체 문자열을 목록으로 나눕니다.
  2. 목록에서 빈 요소를 필터링하십시오.
  3. 단일 요소로 나머지 요소 *를 다시 결합

* 나머지 요소는 구두점 등이 포함 된 단어 나 단어 여야합니다. 나는 이것을 광범위하게 테스트하지는 않았지만 좋은 출발점이되어야합니다. 모두 제일 좋다!


2

파이썬 개발자를위한 솔루션 :

import re

text1 = 'Python      Exercises    Are   Challenging Exercises'
print("Original string: ", text1)
print("Without extra spaces: ", re.sub(' +', ' ', text1))

산출:
Original string: Python Exercises Are Challenging Exercises Without extra spaces: Python Exercises Are Challenging Exercises


1
def unPretty(S):
   # Given a dictionary, JSON, list, float, int, or even a string...
   # return a string stripped of CR, LF replaced by space, with multiple spaces reduced to one.
   return ' '.join(str(S).replace('\n', ' ').replace('\r', '').split())

1

사용자 생성 문자열에 가장 빠른 속도는 다음과 같습니다.

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

단락은 pythonlarry의 포괄적 인 답변 보다 약간 빠릅니다 . 효율성이 높고 단일 공간 다양성의 여분의 공백을 제거하려는 경우에 이것을 찾으십시오 .


1

놀랍게도-다른 모든 게시 된 솔루션보다 훨씬 빠른 간단한 기능을 게시 한 사람은 없습니다. 여기 간다:

def compactSpaces(s):
    os = ""
    for c in s:
        if c != " " or os[-1] != " ":
            os += c 
    return os


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

결과 :

이것은 공백과 탭으로 가득 찬 문자열입니다.


0

단어 사이의 선행, 후행 및 추가 공백을 고려하여 공백을 제거하려면 다음을 사용하십시오.

(?<=\s) +|^ +(?=\s)| (?= +[\n\0])

첫 번째 or는 선행 공백 or을 다루고 , 두 번째 는 문자열 선행 공백의 시작을 다루고, 마지막은 마지막 공백을 처리합니다.

사용 증명을 위해이 링크는 테스트를 제공합니다.

https://regex101.com/r/meBYli/4

이것은 re.split 기능 과 함께 사용됩니다 .


0

대학에서 사용한 간단한 방법이 있습니다.

line = "I     have            a       nice    day."

end = 1000
while end != 0:
    line.replace("  ", " ")
    end -= 1

이것은 모든 이중 공간을 단일 공간으로 대체하고 1000 번 수행합니다. 그것은 당신이 2000 개의 추가 공간을 가질 수 있고 여전히 작동한다는 것을 의미합니다. :)


이것은 (실제적으로) Anakimi의 답변 과 동일합니다 (2 년 전 게시).
피터 Mortensen


0
import re

Text = " You can select below trims for removing white space!!   BR Aliakbar     "
  # trims all white spaces
print('Remove all space:',re.sub(r"\s+", "", Text), sep='') 
# trims left space
print('Remove leading space:', re.sub(r"^\s+", "", Text), sep='') 
# trims right space
print('Remove trailing spaces:', re.sub(r"\s+$", "", Text), sep='')  
# trims both
print('Remove leading and trailing spaces:', re.sub(r"^\s+|\s+$", "", Text), sep='')
# replace more than one white space in the string with one white space
print('Remove more than one space:',re.sub(' +', ' ',Text), sep='') 

결과:

모든 공간 제거 : 공백 제거를 위해 트림을 선택할 수 있습니다 !! Braaikbar 선행 공간 제거 : 공백 제거를 위해 아래 트림을 선택할 수 있습니다 !! BR Aliakbar
후행 공백 제거 : 공백 제거를 위해 아래 트림을 선택할 수 있습니다 !! BR Aliakbar 앞뒤 공백 제거 : 공백 제거를 위해 아래 트림을 선택할 수 있습니다 !! BR Aliakbar 공백 제거 : 공백 제거를 위해 아래 트림을 선택할 수 있습니다 !! BR Aliakbar


-1

다른 예제를 많이 읽지는 ​​않았지만 여러 연속 공백 문자를 통합하기 위해이 방법을 만들었습니다.

라이브러리를 사용하지 않으며 스크립트 길이 측면에서 비교적 길지만 복잡한 구현은 아닙니다.

def spaceMatcher(command):
    """
    Function defined to consolidate multiple whitespace characters in
    strings to a single space
    """
    # Initiate index to flag if more than one consecutive character
    iteration
    space_match = 0
    space_char = ""
    for char in command:
      if char == " ":
          space_match += 1
          space_char += " "
      elif (char != " ") & (space_match > 1):
          new_command = command.replace(space_char, " ")
          space_match = 0
          space_char = ""
      elif char != " ":
          space_match = 0
          space_char = ""
   return new_command

command = None
command = str(input("Please enter a command ->"))
print(spaceMatcher(command))
print(list(spaceMatcher(command)))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.