Предположим, что это строка:
The fox jumped over the log.
Это приведет к:
The fox jumped over the log.
Каков самый простой, 1-2 вкладыш, который может это сделать? Без разделения и перехода в списки...
Предположим, что это строка:
The fox jumped over the log.
Это приведет к:
The fox jumped over the log.
Каков самый простой, 1-2 вкладыш, который может это сделать? Без разделения и перехода в списки...
>>> import re
>>> re.sub(' +',' ','The quick brown fox')
'The quick brown fox'
foo - ваша строка:
" ".join(foo.split())
Будьте осторожны, хотя это удаляет "все пробельные символы (пробел, табуляция, новая строка, возврат, форма)". (Благодаря hhsaffar, см. Комментарии), т.е. "this is \t a test\n"
будет эффективно заканчиваться как "this is a test"
import re
s = "The fox jumped over the log."
re.sub("\s\s+" , " ", s)
или
re.sub("\s\s+", " ", s)
поскольку пробел перед запятой указан как домашнее животное в PEP8, как упоминалось лосом в комментариях.
Использование регулярных выражений с "\ s" и выполнение простой строки .split() также удалит другие пробелы - например, строки новой строки, возврат каретки, вкладки. Если это не требуется, только делать несколько пробелов, я представляю эти примеры.
РЕДАКТИРОВАТЬ: Как я привык делать, я спал на этом и, кроме исправления опечатки на последних результатах (v3.3.3 @64-bit, а не 32-битный), очевидное поразило меня: тестовая строка была довольно тривиальной.
Итак, я получил ... 11 абзацев, 1000 слов, 6665 байт Lorem Ipsum, чтобы получить более-реалистичные тесты времени. Затем я добавил дополнительные пробелы по всей длине:
original_string = ''.join(word + (' ' * random.randint(1, 10)) for word in lorem_ipsum.split(' '))
Я также исправил "правильный join
"; если кто-то заботится, однострочный слой будет по существу делать полосу любых ведущих/конечных пространств, эта исправленная версия сохраняет ведущее/конечное пространство (но только ONE;-). (Я нашел это, потому что случайное расстояние lorem_ipsum
получило дополнительные пробелы на конце и, таким образом, не удалось assert
.)
# 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
ПРИМЕЧАНИЕ. " Имейте в виду, что main while
версия" сделала копию original_string
, как я полагаю, однажды измененный в первом запуске, последовательные прогоны будут быстрее (если только немного). Поскольку это добавляет время, я добавил эту строковую копию в другие две, чтобы времена показывали разницу только в логике.stmt
on 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-loop является самым быстрым, за которым следуют Pythonic string-split/join и regex, тянущие сзади.
Для нетривиальных строк, кажется, есть немного больше, чтобы рассмотреть. 32-битный 2,7? Это регулярное выражение на помощь! 2.7 64-бит? A while
лучше всего подходит с достаточной степенью точности. 32-бит 3.2, перейдите к "правильному" join
. 64-бит 3.3, перейдите в цикл while
. Опять же.
В конце концов, можно улучшить производительность, если/где/когда это необходимо, но всегда лучше запомнить мантру:
IANAL, YMMV, Caveat Emptor!
Приходится соглашаться с комментарием Пола Макгуайра выше. Мне,
' '.join(the_string.split())
Крайне предпочтительнее, чем выводить регулярное выражение.
Мои измерения (Linux, Python 2.5) показывают, что split-then-join будет почти в 5 раз быстрее, чем выполнение re.sub(...), и еще в 3 раза быстрее, если вы предварительно скомпилируете регулярное выражение и выполните операцию многократно. И в любом случае это легче понять - гораздо более питонно.
Аналогично предыдущим решениям, но более конкретным: замените два или более пробела на один:
>>> import re
>>> s = "The fox jumped over the log."
>>> re.sub('\s{2,}', ' ', s)
'The fox jumped over the log.'
Простая душа
>>> import re
>>> s="The fox jumped over the log."
>>> print re.sub('\s+',' ', s)
The fox jumped over the log.
Вы также можете использовать технику разделения строк в Pandas DataFrame без необходимости использовать.apply(..), что полезно, если вам нужно быстро выполнить операцию с большим количеством строк. Вот это на одной строке:
df['message'] = (df['message'].str.split()).str.join(' ')
Другая альтернатива
>>> 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
Одна строка кода для удаления всех дополнительных пробелов до, после и внутри предложения:
sentence = " The fox jumped over the log. "
sentence = ' '.join(filter(None,sentence.split(' ')))
Пояснение:
* Остальные элементы должны быть словами или словами с пунктуациями и т.д. Я не тестировал это широко, но это должно быть хорошей отправной точкой. Все самое лучшее!
import re
string = re.sub('[ \t\n]+', ' ', 'The quick brown \n\n \t fox')
Это удалит все вкладки, новые строки и несколько пробелов с одним пробелом.
Это также работает:
while " " in s:
s=s.replace(" "," ")
Где переменная s представляет вашу строку.
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() )
В некоторых случаях желательно заменить последовательные вхождения каждого символа пробела одним экземпляром этого символа. Для этого вы должны использовать регулярное выражение с обратными ссылками.
(\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'
Самое быстрое, что вы можете получить для пользовательских строк:
if ' ' in text:
while ' ' in text:
text = text.replace(' ', ' ')
Короткое замыкание делает это немного быстрее, чем полный ответ pythonlarry. Пойдите на это, если вы после эффективности, и строго стремитесь отсеять лишние пробелы единого пространства.
Если это пробел, который вы имеете в случае разделения на None, не будет содержать пустую строку в возвращаемом значении.
string='This is a string full of spaces and taps'
string=string.split(' ')
while '' in string:
string.remove('')
string=' '.join(string)
print(string)
Результаты
Это строка, заполненная пробелами и метками
Чтобы удалить пробел, считая ведущее, конечное и дополнительное свободное пространство между словами, используйте:
(? < =\s) + | ^ + (? =\s) | (? = + [\n\0])
первый или имеет дело с ведущим пробелом, второй или имеет дело с началом строки, ведущим пробелом, а последний имеет дело с завершающим пробелом
для доказательства использования эта ссылка предоставит вам тест.
https://regex101.com/r/meBYli/4
сообщите мне, если вы найдете вход, который нарушит этот код регулярного выражения.
ТАКЖЕ - это должно использоваться с функцией re.split
Я не читал много в других примерах, но я только что создал этот метод для объединения нескольких последовательных пробелов.
Он не использует никаких библиотек, и хотя он относительно длинный с точки зрения длины скрипта, он не является сложной реализацией
def spaceMatcher(command):
"""
function defined to consolidate multiple whitespace characters in
strings to a single space
"""
#initiate index to flag if more than 1 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)))
i have tried the following method and it even works with the extreme case
like str1=' i live on earth '
' '.join(str1.split())
but if you prefer regular expression it can be done as:-
re.sub('\s+',' ',str1)
although some preprocessing has to be done in order to remove the trailing and ending space.
У меня есть простой метод, который используется в колледже.
line = "I have a nice day."
end = 1000
while end != 0:
line.replace(" ", " ")
end -= 1
Это заменит каждый двойной пробел одним пробелом и сделает это 1000 раз. Это означает, что вы можете иметь 2000 дополнительных пробелов и все равно будете работать. :)